I'm learning Expect, and I've noticed that my Expect scripts sometimes reach a point where they begin to dump commands without executing them. What causes this to happen? I've scraped Google and a couple Expect tutorials, but the keywords related to this issue are not filtering an answer. Any guidance or references are greatly appreciated.
Example Expect Script:
#!/usr/bin/env expect
set ip [lindex $argv 0]
spawn ssh root#$ip /dir/run.sh
expect {
"password:" {
send "secret_password\n"
}
"No route to host" {
spawn echo "This gets dumped, not executed."
}
}
Output:
$ ./ex.exp 192.168.0.22
spawn ssh root#192.168.0.22 /dir/run.sh
ssh: connect to host 192.168.0.22 port 22: No route to host
spawn echo This gets dumped, not executed.
Echo is not a command, so maybe it displays instead since it doesn't tell it to do anything.
Try this instead:
#!/usr/bin/env expect
set ip [lindex $argv 0]
spawn ssh root#$ip /dir/run.sh
expect {
"password:" {
send "secret_password\n"
}
"No route to host" {
puts stdout "Host not reachable."
}
"Connection refused" {
puts stdout "Host not accepting ssh."
}
}
Related
My expect script:
foreach host $hostlist {
puts $host
set timeout 3
spawn ssh -t -q -o StrictHostKeychecking=no "$user\#$host"
expect {
-re "closed by remote host" { exp_continue }
-re "RSA key fingerprint" { send "yes\r"; exp_continue }
-re "(P|p)assword: " { send "$pass\r"; exp_continue }
-re $prompt { send "$cmd\r" }
eof
}
...
is throwing this error and exits right away.
spawn ssh -t -q -o StrictHostKeychecking=no myuserid#example.net
**expect: spawn id exp4 not open**
while executing
"expect -re $prompt"
("foreach" body line 12)
invoked from within
"foreach host $hostlist {
puts $host
set timeout 3
spawn ssh -t -q -o StrictHostKeychecking=no "$user\#$host"
expect {
-re "closed by rem..."
(file "./a" line 36)
whenever the ssh login attempt encounters some problem on a host like:
kex_exchange_identification: Connection closed by remote host
I tried to put various "expect" regexps but couldn't make it continue to the next host but it abruptly exits.
Anyone know of a trick on how to make it not exit but move onto the next host?
If it's not possible using tcl/expect, would it be possible using the expect module with Python or Perl?
Thank you for your help in advance!
Change
-re "closed by remote host" { exp_continue }
to
-re "closed by remote host" { continue }
You want to go to the next foreach iteration, not loop within this expect command to look for the next pattern.
I'm trying to create an expect script to perform and scp command to copy a given file to a remote machine.
If I run the following script, the scp command fails.
#!/usr/bin/expect -f
set ip_addr [lindex $argv 0]
set in_fname [lindex $argv 1]
set out_fname [lindex $argv 2]
set user [lindex $argv 3]
set password [lindex $argv 4]
set timeout 2
if {[llength $argv] != 5} {
send_user "Usage: ./scp_copy.sh <ip_address> <in_fname> <out_fname> <user> <password>\n"
exit 1
}
spawn scp $in_fname $user#$ip_addr:$out_fname
expect {
(yes/no) {send "yes\r"}
timeout
}
expect {
timeout
{
send_user "FAILED TO PERFORM SCP CMD.\n";
exit 1
}
password:
{
send "$password\r"
}
eof
}
... however, if I remove the 'eof' at the end of the second expect clause and instead create a new expect clause at the end, the scp command works.
expect eof
Please can someone explain this. I'm completely new to expect (and bash) scripts and would be grateful for a simple explanation that helps me understand.
What does 'expect eof' do exactly? Does eof indicate that the spawned process has complete? If so, should I introduce another timeout e.g.
expect {
timeout { exit }
eof
}
What is the difference between the eof being inside the second expect clause and it's own separate expect clause? I was expecting the same effect.
Do I need to call 'close' at the end of an expect script?
Thanks.
I am writing an Expect script that remotes to a server "server2" and executes fileexists.sh that will find if file exists at a particular location.
Bash script - fileexists.sh is as follows:
#!/bin/bash
if [ -s $1 ]; then
echo "non empty file exists."
else
echo "File doesnot exist or is empty."
Expect script - expec is as follows:
#!/usr/bin/expect
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 2]
set rfile [lindex $argv 3]
set prompt "$username* ~]$ "
spawn ssh -q -o StrictHostKeyChecking=no $username#$hostname
expect {
timeout {
puts "\n\nConnection timed out"
exit 1
}
"*assword:" {
send "$password\r"
}
}
expect {
"$prompt" {
puts "Logged in successfully.
}
}
spawn ./fileexists.sh $rfile
set lineterminationChar "\r"
expect {
$lineterminationChar { append output $expect_out(buffer);exp_continue}
eof { append output $expect_out(buffer)}
}
puts $output
When i call the expect script with ./expec user pass server2 /apps/bin/file.p I get output as "File doesnot exist or is empty." although the file exists at its location on server2.
i checked using expect:
if {[file exists $rfile]} { puts "file exists" }
And output i get is "file exists".
Seems to be something with spawn that I am unable to figure out.
To check on the remote host, do this (I assume you are logging in to a linux machine, or a machine with GNU stat): untested
send -- "stat -c '%s' '$rfile'\r"
expect {
-re {\r\n(\d+)\r\n} {
puts "$rfile exists with size $expect_out(1,string)"
}
-gl {*No such file or directory*} {
puts "$rfile does not exist"
}
}
send "exit\r"
expect eof
I have a bash script that calls an expect script with a password that initiates the ssh process:
#!/usr/bin/bash
/usr/bin/expect $PWD/sshScript.exp $SSHPASSWORD
The expect script calls the ssh command, waits for prompt to enter password and sends in the password.
#!/usr/bin/expect
set password [lindex $argv 0];
spawn ssh -o "StrictHostKeyChecking no" username#host
expect "Enter your AD Password:" {
send "$password\r"
}
I can get the remote server to ssh correctly and display the [user#host ~]$ but I want to add to the expect script a way to automatically run a bash script that is stored in the same location as the other two scripts.
I've tried to
a) scp the file to the remote and call it in the server but I can't seem to get expect to send any text pass the password
b) do spawn ssh -o "StrictHostKeyChecking no" username#host < secondscript.shto send in the script to run but it won't wait for the password to be entered before trying to run the script.
You may combine you bash and expect script together and use it to copy the 3rd bash script to the remote server, execute it and return the output.
Here's a simple NON-TESTED example:
#!/bin/bash
[... other bash code here ...]
SCRIPT='/path/to/script/to/run/remotely.sh'
LOGIN='test'
IP='your ip or hostname'
LOCATION='/destination/path/to/script/to/run/remotely.sh'
### start expect part here, you may add '-d' after 'expect' for debug
/usr/bin/expect << EOD
### set a 3 minute timeout
set timeout 180
### copy the script you wish to run on the remote machine
spawn scp -o StrictHostKeyChecking=no -p $SCRIPT $LOGIN#$IP:$LOCATION
expect {
timeout { send_user "\n# TIMED OUT. HOST NOT REACHABLE #\n"; exit 3 }
"*assword: "
}
send "your_password\r"
expect {
"*assword: " { send_user "\n# Incorrect Password. Login Failed. #\n"; exit 4 }
"100%" { send_user "\nFile copied\n" }
}
### ssh to remote server to run script
spawn ssh $LOGIN#$IP
expect {
timeout { send_user "\n# TIMED OUT. SSH DAEMON or PORT 22 CLOSED #\n"; exit 6 }
"*assword: "
}
send "your_password\r"
expect {
timeout { send_user "\n# TIMED OUT. PROMPT NOT RECOGNISED! #\n"; exit 7 }
### expect the prompt symbol
-re {[#>$] }
## execute your script on the remote machine
send "$LOCATION\r"
expect {
"enter what you expect here" { send_user "\nRESULT: Message based on what you set the expect to read $IP\n" }
-re {[#>$] }
}
[... other expect code here ... ]
### exit remote ssh session
send "exit\r"
### end of expect part of script
EOD
### continue bash script here
[... other bash code here ...]
Im executing the remote script and checking return status of the script but if I do in the following way its returning the status of the password but not the status of the called script.How can I get the return status of the called script. Please help thanks in advance.
#!/usr/bin/expect
proc auto { } {
global argv
set timeout 120
set ip XXXX.XXX.XX.XX
set user name
set password pass
set ssh_opts {-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no}
set script /path-to-script/test.sh
spawn ssh {*}$ssh_opts $user#$ip bash $script {*}$argv
expect "Password:"
send "$password\r"
send "echo $?\r"
expect {
"0\r" { puts "Test passed."; }
timeout { puts "Test failed."; }
}
expect eof
}
auto {*}$argv
You're automating ssh bash remote_script, so you're not going to get a shell prompt where you can echo $? -- ssh will launch your script and then exit.
What you need to do is get the exit status of the spawned process (ssh is supposed to exit with the remote command's exit status). expect's wait command gets you the exit status (among other info)
spawn ssh {*}$ssh_opts $user#$ip bash $script {*}$argv
expect {
"Password:" { send "$password\r"; exp_continue }
timeout { puts "Test failed." }
eof
}
# ssh command is now finished
exp_close
set info [wait]
# [lindex $info 0] is the PID of the ssh process
# [lindex $info 1] is the spawn id
# [lindex $info 2] is the success/failure indicator
if {[lindex $info 2] == 0} {
puts "exit status = [lindex $info 3]"
} else {
puts "error code = [lindex $info 3]"
}