Linux – use expect in shell script

expectlinuxshell

I need to pass two arguments to expect, first one is the command to execute, the second one is the password.

here's my expect.sh

#!/usr/bin/expect
spawn [lrange $argv 0 0]
expect "password:"
send [lindex $argv 1]
interact

main script:

./expect.sh "ssh root@$SERVER1"  $SERVER1_PASS

error:

couldn't execute "{ssh root@xxx.xxx.xx.xxx}": no such file or directory
    while executing
"spawn [lrange $argv 0 0]"
    (file "./expect.sh" line 2)

why?

Best Answer

As far as I can tell, spawn's first argument needs to be a string, not a list of string.

And trying to pass a multi-word command line as a single string is going to cause problems. I think you'd have to split on spaces before calling spawn, and that's going to break if one argument contains a space. Maybe it's better to specify the password as the first argument, and the command as the rest of the arguments.

So try something like:

#!/usr/bin/expect
spawn [lindex $argv 1] [lrange $argv 2 end]
expect "password:"
send [lindex $argv 0]
interact

But then even that doesn't work.

According to Re: expect - spawn fails with argument list on comp.lang.tcl (Google Groups version), we have to call eval to split the list.

So the answer should be:

#!/usr/bin/expect
eval spawn [lrange $argv 1 end]
expect "password:"
send [lindex $argv 0]
interact

Finally, you need to be sending Enter after the password, so you want:

#!/usr/bin/expect
eval spawn [lrange $argv 1 end]
expect "password:"
send [lindex $argv 0]
send '\r'
interact

And then switch the order and don't quote the command when calling it:

./expect.sh "$SERVER1_PASS" ssh root@$SERVER1

But others have already done this. We don't need to re-invent the wheel.

See e.g. expect ssh login script