What I am trying to do is to:
Create a .exp file, which will read from the *.txt file from the same directory and parse all the content in the text file into a string variable in the expect script.
Loop the string, which contains a series of host names, and excecute a series of command until the string is enumerated.
So what the script does, is read a series of hostname from a txt file in the same directory, and then read them into a string, and the .exp file will auto log into each of them and excecute a series of commands.
I have the following code written but it's not working:
#!/usr/bin/expect
set timeout 20
set user test
set password test
set fp [open ./*.txt r]
set scp [read -nonewline $fp]
close $fp
spawn ssh $user#$host
expect "password"
send "$password\r"
expect "host1"
send "$scp\r"
expect "host1"
send "exit\r"
Any help is greatly appreciated....
The code should read the contents of the two files into lists of lines, then iterate over them. It ends up like this:
# Set up various other variables here ($user, $password)
# Get the list of hosts, one per line #####
set f [open "host.txt"]
set hosts [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "commands.txt"]
set commands [split [read $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hosts {
spawn ssh $user#host
expect "password:"
send "$password\r"
# Iterate over the commands
foreach cmd $commands {
expect "% "
send "$cmd\r"
}
# Tidy up
expect "% "
send "exit\r"
expect eof
close
}
You could refactor this a bit with a worker procedure or two, but that's the basic idea.
I'd refactor a bit:
#!/usr/bin/expect
set timeout 20
set user test
set password test
proc check_host {hostname} {
global user passwordt
spawn ssh $user#$hostname
expect "password"
send "$password\r"
expect "% " ;# adjust to suit the prompt accordingly
send "some command\r"
expect "% " ;# adjust to suit the prompt accordingly
send "exit\r"
expect eof
}
set fp [open commands.txt r]
while {[gets $fp line] != -1} {
check_host $line
}
close $fp
Using any of the two solutions here, I would also create a logfile that you can view at a later time. Makes it easy to troubleshoot any problems after the script is run, especially if you're configuring several hundred hosts.
Add:
log_file -a [log file name]
Before your loop.
Cheers,
K
Related
I am attempting to automate the change of switch configurations on multiple cisco switches. I get all the way to the config section and when the config.txt variable is sent, the output has curly brackets at the end and is not a valid command. Here is the output and below that I will post the code.
All I am trying to do is login to my switch and run the following command
configure replace flash:/thenameofconfig
The script will loop through multiple switches in the device list and apply the correct config based o
IL-test-SW1#configure replace flash:/il-test-sw2-confg} {}
Code:
#!/usr/bin/expect -f
# Set up various other variables here ($user, $password)
set username user
set password user
set enablepassword user
# Log results
#log_file -a ~/results.log
log_file -a /tmp/results.log
# Get the list of hosts, one per line #####
set f [open "device-list.txt"]
set hostname [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "configs.txt"]
set configs [split [read $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hostname {
# Don't check keys
spawn ssh -o StrictHostKeyChecking=no $username\#$hostname
# spawn ssh $user#host
# expect "password:"
# send "$password\r"
# Allow this script to handle ssh connection issues
expect {
timeout { send_user "\nTimeout Exceeded - Check Host\n"; exit 1 }
eof { send_user "\nSSH Connection To $hostname Failed\n"; exit 1 }
"*#" {}
"*assword:" {
send "$password\n"
}
}
# If we're not already in enable mode, get us there
expect {
default { send_user "\nEnable Mode Failed - Check Password\n"; exit 1 }
"*#" {}
"*>" {
send "enable\n"
expect "*assword"
send "$enablepassword\n"
expect "*#"
}
}
# Let's go to configure mode
send "conf t\n"
expect "(config)#"
send "shell processing full\n"
expect "(config)#"
send "end\n"
expect "*#"
#Iterate over the commands
foreach config $configs {
expect "*#"
send "$configs\n"
expect "\[no]:"
send "y\n"
expect "*#"
}
# Tidy up
# expect "*#"
# send "exit\r"
# expect eof
# close
send "exit\n"
expect ":~\$"
exit
}
Cannot seem to get rid of the {} at the end of the configure replace command.
Any help will be greatly appreciated.
Figured it out. Was the following line
set hostname [split [read $f] "\n"]
Needs to be:
set hostname [split [read -nonewline $f] "\n"]
I am trying to run the below expect scriipt to login to the multiple hosts and run the some commands on those hosts.
I have two files 1) host.txt which contains host names another 2) commands.txt which contains commans to execute.
Though, while i am running it its through an error which i have given below.. Please advise .. I went through all the solutions over the stackoverflow but did not get things working ..
SCRIPT CODE .....
$ cat myexpc
#!/usr/bin/expect -f
# Set up various other variables here ($user, $password)
set timeout 20
set user karn
set password 123
# Get the list of hosts, one per line #####
set f [open "host.txt"]
set hosts [split [read $f] "\n"]
close $f
# Get the commands to run, one per line
set f [open "commands.txt"]
set commands [split [ read $f] "\n"]
close $f
# Iterate over the hosts
foreach host $hosts {
spawn ssh $user#$host
expect "password:"
send "$password\r"
# Iterate over the commands
foreach cmd $commands {
expect "% "
send "$cmd\r"
}
# Tidy up
expect "% "
send "continue\r"
expect eof
close
}
====================
SCRIPT RUN & FAILURE CODE ..........
$ ./myexpc
spawn ssh karn#Server1
The authenticity of host 'server1 (192.2.47.194)' can't be established.
RSA key fingerprint is 33:r3:31:dd:a1:8a:38:08:b7:b1:e1:24:bc:cd:e2:5c.
Are you sure you want to continue connecting (yes/no)? yes
123
Please type 'yes' or 'no': yes
/bin/grep 192.17.14.1 /etc/ldap.conf /etc/resolv.conf
Please type 'yes' or 'no': yes
y
y
y
y
y
y
it keeps on running
I would like to run this script in a loop.
What is needs to do is read a file with in that file IP addresses like:
10.0.0.0
10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
And run this script on every ip listed above here.
This is what i have:
#!/usr/bin/expect
spawn telnet 10.0.0.0
expect "User Name :"
send "username\r"
expect "Password :"
send "password\r"
expect ">"
send "4\r"
expect "*#"
exit
How do i get the script above working every IP in a txt file.
You can read the file within your expect script.
Open the file and assign the file descriptor to a variable, read each line and execute the above code you wrote.
set fildes [open "myhosts.txt" r]
set ip [gets $fildes]
while {[string length $ip] > 0} {
spawn telnet $ip
expect "User Name :"
send "username\r"
expect "Password :"
send "password\r"
expect ">"
send "4\r"
expect "*#"
exit
set ip [gets $fildes]
}
close $fildes
I'm not an expert with expect, but the first thing you need to do is change your expect script to accept arguments. It should work like this (looks like you'll need -f in #!/usr/bin/expect):
#!/usr/bin/expect -f
set ip [lindex $argv 0]
spawn telnet $ip
...
Then you can simply iterate over the list of your IPs in your bash script:
while read ip ; do
myExpectScript $ip
done < list_of_ip.txt
This is just a comment on #user3088572's answer. The idiomatic way to read a file line by line is:
set fildes [open "myhosts.txt" r]
while {[gets $fildes ip] != -1} {
# do something with $ip
}
close $fildes
I writing a script to read user name, password and host info from a file.
I then parse this info to get the variables. I would then like to add these variables to an expect script that reads all the ip address in my file and performs certain commands on the remote devices that I am trying to log into. The script works when it connects to a known host however What I am seeing is that there is one device that is not up and running and the system promps with the following error.
ssh: connect to host 192.168.3.2 port 22: No route to host
the file
I would like to do 2 things
1. Skip the host and move to the next host
2. log the host that is down to another file so that I can troubleshoot the network issue to that host.
Please see the script below. Please any help is greatly accepted.
#! /usr/bin/expect -f
## Read the file
set fid [open /csv_pars/employee1.csv]
set content [read $fid]
close $fid
## Split into records on newlines
set records [split $content "\n"]
## Iterate over the records
foreach rec $records {
## Split into fields on comma
set fields [split $rec ","]
## Assign fields to variables and print some out...
lassign $fields\ ipaddr username password
puts "$ipaddr"
puts "$username"
puts "$password"
if {$ipaddr == ""} continue
spawn ssh -X "$username#$ipaddr"
sleep 2
expect "password:"
sleep 2
send "$pass\r"
expect "$"
send -- "ls -l\r"
expect "$"
send -- "exit\r"
expect eof
}
You need to expect to see one of two things: the password prompt, or the error message:
spawn ssh -X "$username#$ipaddr"
expect {
-re "password: ?$" {
send "$pass\r"
expect "$"
send -- "ls -l\r"
expect "$"
send -- "exit\r"
expect eof
}
"No route to host" {
set fid [open error.log a]
puts $fid "[clock format [clock seconds]]: No route to host $ipaddr"
close $fid
}
}
I have a bash+expect script which has to connect via ssh to the remote comp (and i can't use ssh keys, need password identification in here), read the file there, find specific line with the "hostname" (like "hostname aaaa1111") and store this hostname into the variable to be used after while. How can i get the value of the "hostname" parameter? I thought that line content will be in $expect_out(buffer) variable (so i can scan it and analyze), but it's not. My script is:
#!/bin/bash
----bash part----
/usr/bin/expect << ENDOFEXPECT
spawn bash -c "ssh root#$IP"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \r"
expect ":~#"
set line $expect_out(buffer)
puts "line = $line, expect_out(buffer) = $expect_out(buffer)"
...more script...
ENDOFEXPECT
When i try to see line variable, i see only this: line = , expect_out(buffer) = (buffer) What is the right way to get the line from the file into the variable?
Or is it possible to open the file on the remote computer with expect, scan the file and get what i need to the variable?
Here http://en.wikipedia.org/wiki/Expect there is an example:
# Send the prebuilt command, and then wait for another shell prompt.
send "$my_command\r"
expect "%"
# Capture the results of the command into a variable. This can be displayed,
set results $expect_out(buffer)
seems that it doesn't work in this case?
You might just want to try and do it all from expect, as expect can control bash.
The following should do what you've described. Not sure if this is exactly what you are trying to do.
#!/bin/sh
# the next line restarts using tclsh \
exec expect "$0" "$#"
spawn bash
send "ssh root#$IP\r"
expect "password:"
send "xxxx\r"
expect ":~#"
send "cat /etc/rc.d/rc.local |grep hostname \n"
expect ":~#"
set extractedOutput $expect_out(buffer)
set list [split $extractedOutput "\n"]
foreach line $list {
set re {(?x)
.*
(*)
-S.*
}
regexp $re $line total extractedValue
if {[info exists extractedValue] && [string length $extractedValue] > 1} {
set exportValue $extractedValue
break # We've got a match!
}
send "exit\r" # disconnect from the ssh session
if {[info exists exportValue] && [string length $exportValue] > 1}{
send "export VARIABLE $exportValue\r"
} else {
send_user "No exportValue was found - exiting\n"
send "exit\r"
close
exit 1
}
# now you can do more things in bash if you like