exit expect {} without timeout

Chen Levy picture Chen Levy · Jun 29, 2010 · Viewed 23k times · Source

I am struggling with the classic problem of typing password automatically in ssh, and like everybody else I am stumbling in the dark regarding expect. Finally I cobbled together a script that kinda work:

#!/usr/bin/expect -f

# command line args
set user_at_host [lrange $argv 0 0]
set password [lrange $argv 1 1]

set timeout 1

# ssh command
spawn ssh -S ~/.ssh/tmp.$user_at_host -M -N -f $user_at_host

# deal with ssh prompts
expect {
    "*yes/no*" { send "yes\r" ; exp_continue }
    "*assword:" { send "$password\r" ; exp_continue }
}

This script terminates only thanks to the timeout 1 line, without it it simply hangs, and will terminate only by user interaction (^C).

When the spawn line was a straight forward ssh command, the script terminated right away, however this is not your straight forward ssh. The thing that might be different is the -f option that make it run in the background (but I tried the script without it to no avail).

I read that interact or expect eof might help, but I wasn't able to find the correct incantation that will actually do it.

My question (I think) is How to make an expect script, that spawn a background process, terminate without a timeout?


Edit: I should have expected (no pun intended) the "use passwordless ssh authentication" answer. While this is a sound advice, it is not the appropriate solution in my scenario: Automatic testing a vanilla installed system in a trusted environment, where adding trusted keys to the image is not desirable / possible.

Answer

glenn jackman picture glenn jackman · Jun 30, 2010

You probably want:

expect {
    "*yes/no*" { send "yes\r" ; exp_continue }
    "*assword:" { send "${password}\r" }
}
expect $the_prompt
send "exit\r"
expect eof

UPDATE

I missed that you are sending a command via ssh. I think all you need is this:

spawn ssh a@b foo bar baz
expect {
    "*yes/no*" { send "yes\r" ; exp_continue }
    "*assword:" { send "${password}\r" }
    eof
}

You'd hit eof when the foo command completes.