Tutorial :Using Expect to administer machines via SSH, but does not complete all tasks


*Please do not pile on and tell me to just use SSH keys. If it bugs you that this is the way I am doing it, pretend that I am trying to telnet in instead. :-) *

I am using an expect script to run some routine commands on a set of servers under my control via ssh. The script should run set of commands (eg svn update ~/folderx\r") on each of the machines. My current script does everything I want it to do... sometimes. Other times it exits the ssh connection before it completes one of the last few commands.

Any thoughts on how I can make the connection stay until all of the commands are completed? The code below successfully logs on, successfully runs the first two commands or so (ap-get update and one of the svn updates) and then disconnects.

#!/usr/bin/expect -f    spawn ssh username@ipaddress  set timeout -1  expect "Are you sure you want to continue connecting" {send "yes\r"; exp_continue} "password:" {send "*******\r"; exp_continue      } "username@machine" {send "sudo apt-get update\r"}  expect "password" {send "*******\r"; exp_continue} "username@machine" {send "sudo svn update ~/folder1\r"}  expect "password" {send "*******\r"; exp_continue} "username@machine" {send "sudo svn update ~/folder2\r"}  expect "password" {send "*******\r"; exp_continue} "username@machine" {send "sudo svn update ~/folder3\r"}  expect "password" {send "*******\r"; exp_continue} "username@machine" {send "sudo reboot\r"}  close  


Using Expect is generally the wrong way to do this kind of thing. The right way is to set up ssh keys so that you can ssh and run commands on the remote machine without supplying a password. Here's how to do that:

0. Create public/private key pair on local machine.     (Only needs to be done once on local machine for all remote machines.)     Go to the ~/.ssh directory on your local machine and do this:     % ssh-keygen -t rsa  1. Copy the public key to the remote machine:     % scp ~/.ssh/id_rsa.pub you@foo.com:.  2. Append that key to the authorized_keys file on the remote machine:     % ssh you@foo.com 'cat id_rsa.pub >> .ssh/authorized_keys; /bin/rm id_rsa.pub'  3. Finally, in case it doesn't work, check permissions, which must be just so:      (or maybe it's just that they can't be group/world writeable)     % cd ~; ls -ld . .ssh .ssh/authorized_keys       drwxr-xr-x  .       drwxr-xr-x  .ssh       -rw-r--r--  .ssh/authorized_keys  

Here's a script that does the above in one fell swoop:


You can then run commands on the remote machine like so:

ssh alice@remote.com ./foo args  

To run commands on the remote machine with sudo, however, may be another story. Hopefully others can chime in about that. But as a first step you should avoid Expect for the initial login.


It turns out that the reason it was exiting earlier was that the prompt pattern that I was matching against matched not only the prompt, but also some of the output from the svn commands I was running. I was matching against only the "username" portion of the prompt pattern (the prompt form was "username@machine:~$"). Once I altered the script to match only "username@" it began to work as expected.

p.s. the ssh script that dreeves links to above works very nicely.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »