Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

exit expect {} without timeout

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.

like image 370
Chen Levy Avatar asked Jun 29 '10 13:06

Chen Levy


2 Answers

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.

like image 184
glenn jackman Avatar answered Oct 08 '22 00:10

glenn jackman


OK, so I found a permutation that seem to work --

First I need a wrapper script that will give an indication when done:

#!/bin/bash
"$@"
echo "done"

Then the expect script becomes:

#!/usr/bin/expect -f
set user_at_host [lrange $argv 0 0]
set password [lrange $argv 1 1]

# no need for timeout 1
set timeout 60

# use the wrapper
spawn wrapper ssh -S ~/.ssh/tmp.$user_at_host -M -N -f $user_at_host

expect {
   "*yes/no*" { send "yes\r" ; exp_continue }
   "*assword:" { send "$password\r" ; exp_continue }
   # use the wrapper
   "done" { exit }
}

Thanks for Douglas Leeder (voted up) and glenn jackman (voted up) for the helpful advice. I will gladly un-accept this answer, and accept any more elegant answer, perhaps one that do away with the wrapper script.

Thank you all for your attention.

like image 20
Chen Levy Avatar answered Oct 07 '22 22:10

Chen Levy