Training, Open Source computer languages
PerlPHPPythonMySQLApache / TomcatTclRubyJavaC and C++LinuxCSS 
Search for:
Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
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 me

Writing 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:
I am TCL newbie and I thought I had copied all the best code on the Internet but it is not working for me

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 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.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2014: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 899360 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho