Daryl Rose wrote:
> I'm beginning to see my problem, I just don't know how to solve it yet.
> Looking over the debug output, I see that the output from scp is
> causing problems.
Nop, the problem is somewhere else.
> while {[gets $file hosts] != -1} {
> set count 0
> spawn scp $hosts:$remote_file $local_file/$hosts:userinfo
> while {$count<$num_passwd} {
> expect "*assword:" {
> send $password($count)\r
> }
> incr count
> }
> expect eof
> }
In the code above, suppose that the first password was matched, your
inner [while] will again expect for "*assword:", which will never come
again since file transfer has already started. This is shown in the
debugged output:
> expect: does "Password: " (spawn_id exp5) match glob pattern
> "*assword:"? yes
> expect: set expect_out(0,string) "Password:"
> expect: set expect_out(spawn_id) "exp5"
> expect: set expect_out(buffer) "Password:"
> send: sending "sample\r" to { exp5 }
You send the first password "sample\r", but you still look for
"*assword:?" even though the file transfer has started.
> expect: does " " (spawn_id exp5) match glob pattern "*assword:"? no
> expect: does " \r\n" (spawn_id exp5) match glob pattern "*assword:"? no
> passwd
> 0% 0 0.0KB/s --:-- ETA
> expect: does " \r\n\rpasswd
The file transfer finishes and the scp terminates (expect reads eof),
> 100% 690 0.0KB/s 00:00 \r\n" (spawn_id exp5) match glob
> pattern "*assword:"? no
> expect: read eof
But you still look for "*assword:" and here you get an error because
the process has terminated and you can't read from the closed "spawn
id" associated with the spawned process.
> expect: spawn id exp5 not open
> while executing
> "expect "*assword:" {
To solve this problem the code needs to know when to look for
"*assword:" and when to stop looking for it and waiting for eof
instead. Instead of looping inside a [while], you can loop instead
inside [expect] itself, sending a new password each time prompted.
Another problem with this code is that it does not clean after the
terminated processes. Each time an scp terminates it will leave behind
a defunct process, and this will probably cause your script to fail
after polling around one hundred hosts or so. You need to collect the
terminated process data before you spawn another one. You do this with
the expect [wait] command.
The last thing, the leading asterisk in "*assword:" is really redundant
in addition that it can be tricky. It is not generally a good practice
to start your pattern with an asterisk.
Well, finally, I would write this code like this:
while {[gets $file hosts] != -1} {
set count 0
spawn scp $hosts:$remote_file $local_file/$hosts:userinfo
expect {
-re "assword:.?$" {
exp_send $password($count)\r
incr count
exp_continue
}
"ETA" {exp_continue}
eof {
catch {close -i $spawn_id}
wait -nowait -i $spawn_id
}
}
}
and if you want to turn OFF the output of the process, use [log_user 0]
before you spawn the process.
and welcome to Tcl!
Khaled
Received on Thu Sep 29 14:19:02 2005