2

I have this expect script, that will log into a host, run a command, return it's contents and exit. What sort of cleanup/proper exiting needs to happen when I've finished running my command? This command will always return something, the larger problem or issue I think I should be handling is if either SSH hangs, or if logging in as the admin user hangs. I thought I might have been handling that via timeout, but I am unsure:

#!/usr/bin/expect -f

set timeout 10 match_max 100000 set hostname [lindex $argv 0]

spawn /usr/bin/ssh -o "StrictHostKeyChecking no" admin@$hostname expect "password:" send -- "redactedSSHpassword\r" expect "Username:" send -- "admin\r" expect "password:" send -- "redacted\r" expect -- "#" send -- "show stat summary\r" expect -- "#"

I also don't understand the proper way of exiting this script and making sure I'm not leaving a stale session around.

Kahn
  • 1,702
  • 2
  • 20
  • 39

2 Answers2

3

If you get a timeout then the expect statements fail and it just goes on an executes the next statement. This will probably make no sense but it does mean that things like the following can happen.

You expect "Username:" and get it.
You send "admin\r", and get back "No such username"
You expect "password:" but don't get it because you got the "No such username" message, so you timeout.
You send "redacted\r" and get back "redacted: no such command" but redacted has been added to the history on the machine.
You expect "*#*" ....

When your script reaches the end it will exit. At this point the ssh will be reparented to PID 1. ssh will detect EOF on its standard input and will pass this on and will exit. So you probably don't need any extra cleanup.

If this was my script I would write a small procedure

proc lookfor {pat} {
    expect timeout { send_user "timeout looking for '$pat'\r\n" ; exit } $pat
}

and replace all calls of expect with lookfor to get it to exit as soon as a match fails. One could use expect_after or expect_before but lookfor give an easy diagnostic.

icarus
  • 17,920
0

Complementing icarus' helpful answer, you can add this at the beginning of your expect script to make it exit on any timeout:

expect_before {
    timeout { puts "timeout"; exit 1 }
}

This will prefix every expect command by the given handler. If a timeout occurs, it will print "timeout" and then exit with a return code of 1.