Question

I am using the following Expect script for remote SSH login to a Raspberry Pi and am executing the commands:

#!/usr/bin/expect
set timeout 60
spawn ssh [lindex $argv 1]@[lindex $argv 0]
expect "yes/no" {
    send "yes\r"
    expect "*?assword" { send "[lindex $argv 2]\r" }
    } "*?assword" { send "[lindex $argv 2]\r" }
expect "pi@raspberrypi ~ $ " {
    send "ls -la\r"
    }
interact

The problem is that this script is able to log in into the Raspberry Pi, but when it comes to the line for executing the "ls -la" command, nothing happens. How can I fix this script? Where am I making the mistake?

OK, if I put the

exp_internal 1

line in my script, I get the following output in the where matching fails:

expect: does ": \r\nLinux raspberrypi 3.10.24+ #614 PREEMPT Thu Dec 19 20:38:42 GMT 2013 armv6l\r\n\r\nThe programs included with the Debian GNU/Linux system are free software;\r\nthe exact distribution terms for each program are described in the\r\nindividual files in /usr/share/doc/*/copyright.\r\n\r\nDebian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent\r\npermitted by applicable law.\r\nLast login: Mon Mar 3 19:00:11 2014 from 192.168.1.200\r\r\n\u001b]0;pi@raspberrypi: ~\u0007\u001b[01;32mpi@raspberrypi\u001b[00m \u001b[01;34m~ $\u001b[00m " (spawn_id exp6) match glob pattern "*pi@raspberrypi ~ $*"? no

Shouldn't this matching be true?

Was it helpful?

Solution

You should be using exp_continue to reenter your Expect loop after the password and authenticity checks are done. Try the below:

#!/usr/bin/expect

set prompt "pi@raspberrypi ~ $ "
spawn ssh [lindex $argv 1]@[lindex $argv 0]

set timeout 5
expect {
    timeout {
        puts "Connection timed out"
        exit 1
    }

    "yes/no" {
        send "yes\r"
        exp_continue
    }

    "assword:" {
        send -- "[lindex $argv 2]\r"
        exp_continue
    }

    "$prompt" {
        send "ls -la\r"
    }
}

This is an extract taken from Exploring Expect regarding exp_continue by Don Libes:

When executed as an Expect action, the command exp_continue causes control to be continued inside the current Expect command. Expect continues trying to match the pattern, but from where it left off after the previous match. Expect effectively repeats its search as if it had been invoked again.

OTHER TIPS

You might have a look at this... it takes a list of commands, contained in a file, and executes them on the remote host by interactively logging in and executing them one-at-a-time on the remote machine. You can turn on logging if you want to capture output, and you'll need to tweak it to handle your computer (or other device's) prompts:

    #!/usr/bin/expect
    #
    # Read a list of commands and execute them on remote host
    #
    # WA2IAC 3/9/2015
    #

    spawn ssh -l username target_host
    expect "ord\\: "
    send "your_password\r"
    set handle [ open commandfile.txt r ]
    while { ! [eof $handle] } {
        gets $handle buf
        expect "\\$"
        send "$buf\r"
        }
    interact

You can flesh this out by setting a timeout and handling things that can go wrong (see snippet above). Remove the "interact" statement to have the script exit when done (you could use a shell loop to execute this for a number of hosts/devices).

I've used this to send commands routers to update static routes, but it has many other uses. I got it from here: http://wa2iac.com/wiki/index.php?title=Expect_remote_commands

I also recommend making sure you expect for the very last string pattern that is outputted by you previous send command when using the Expect command.

I tell you this because Expect's output is saved in a buffer, and the buffer can only hold so much data. I wrestled with this issue for a while not finding out why my expect -re{} command was not being picked up correctly. I was expecting the first few string patterns that my previous send command outputted.

I should have been looking for the last String pattern, since this string pattern was sure to be in Expect's buffer, and the first strings had been deleted since the buffer could only hold so much data. The output from my send command was a bit long.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top