| |||||||||||
spawn and foreach in expect Posted by chies (chies), 18 July 2007 I am TCL newbie and I thought I had copied all the best code on the Internet but it is not working for meWriting an expect script to ssh into a list of servers and do some stuff. Input: # Get password stty -echo set timeout -1 send_user "Enter password: " expect_user { -re "(.*)\n" { set PASSWORD $expect_out(1,string) } } set fp [open "hosts" r] set hosts [read $fp] close $fp set hostlist [ split $hosts "\n" ] puts $hostlist foreach host $hostlist { puts $host spawn ssh $host "Do some other stuff" } End Input Output: host1 host2 {} host1 spawn ssh host1 Password: host2 spawn ssh host2 Password: spawn ssh ssh: : Name or service not known send: spawn id exp6 not open while executing "send "$PASSWORD\r"" ("foreach" body line invoked from within "foreach host $hostlist { puts $host spawn ssh $host expect { timeout exit "Password:*" } send "$PASSWORD\r" expect { "*'s password" {puts "#-#\n..." (file "./expect.tcl" line 2 End Output Two things: Why does the list have a set of empty brackets at the end which foreach sees as an element? Why does foreach move on to the next item in the list before it has executed all the commands in the loop? expect version 5.42.1 tcl-8.4.7-2 RHEL 4U4 I ran this with a slightly newer version of expect and tcl but had the same result. Any help is greatly appreciated . Posted by admin (Graham Ellis), 19 July 2007 on 07/18/07 at 20:33:43, chies wrote:
Expect code is notoriorsly dependent on the system on which it is running as you're using it to paste a huge number of utilities together each of which may vary a little in how it works - really subtle changes. You've got a huge pile of bits of software, each of which is good in its own right, but as you add them on of of each other and combine them, you'll find that the very top layer that ties them all together has to be adjusted to work. I'm not surprised that the code doesn't just work for you, and the best way to correct that is to investigate and understand the detail of what's going and fix the problems. The empty element is probably an empty line at the end of your file. Spawn starts another process ... so even while your spawned command is still running, your foreach loop can proceed - it depends on just what you have in your "do some other stuff". I am concerned at the apparent lack of access to ssh - although you don't comment, I think this might be an underlying problem. Posted by cwjolly (cwjolly), 24 August 2007 Why does the list have a set of empty brackets at the end which foreach sees as an element? This means that your file has a \n as the last character. For instance if your string is a\nb you will get {a b } as your list when you split. If your string is a\nb\n you will get { a b {} } . Why does foreach move on to the next item in the list before it has executed all the commands in the loop? From the error you get and the code you've provided you have not shown us how the expect call is being made. There is nothing in the spawn command that says stop and wait. All it does is fork a child, exec your program and sets up the pipes between your script and the child and returns without blocking. So you are free to ignore what spawn has given you or you can interact with it. In this case ( at least what you show) is you never call expect in the loop so you just spawning a bunch of processes and then exiting. Some comments since you have not included all your code. From the error message you are using puts inside of a call to expect ... always use send_user. You call stty -echo but never call the counterpart to restore echoing stty echo this should be done afte getting the password. Your code cannot find the ssh executable. You should check for this by using : set SSH [auto_execok ssh ] if { [ string length $SSH] == 0 } { puts "Unable to find ssh; Make sure your PATH variable has the directory where ssh is located in it" exit 1 } then use spawn $SSH $host I you have alot of hosts you will eventually be unable to spawn anymore unless you exp_wait then exp_close. Here is a template that you can use in your scripts to always write your expect loops. set pid spawn -noecho <command here> set my_id $spawn_id; set bad 0; set done 0; exp_internal 0; # set to one for extensive debug log_user 0; # set to one to watch action expect { -i $my_id -re {<what you expect here>} { exp_continue; } timeout { send_user "timeout " set bad 1 } fullbuffer { send_user " buffer is full " exp_continue; } eof { send_user "Eof detected " set done 1 ; } } set exitstatus [ exp_wait -i $my_id ]; catch { exp_close -i $my_id }; Carl This page is a thread posted to the opentalk forum
at www.opentalk.org.uk and
archived here for reference. To jump to the archive index please
follow this link.
|
| ||||||||||
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho |