From: howardbryden on
I'm attempting to pipe commands to ssh(1) while also using Expect to
handle the optional dialog that ssh can generate. I'm using version
5.43.0 under HP-UX 11.11.

My Expect script is as follows:

##########
if [catch "spawn -noecho /usr/bin/ssh -i ~/.ssh/id_rsa_SVC -l admin
dessvc" reason] {
send_error -- "x: Failed to spawn SSH: $reason\n"
exit 1
}

set timeout -1
log_user 0

expect {
-exact "Are you sure you want to continue connecting (yes/no)? " {
send -- "yes\r"; exp_continue }
-exact "yes\r\n" exp_continue
-re "Warning: Permanently added '.*' (.*) to the list of known
hosts.\r\r\n" exp_continue
-exact "Enter passphrase for key '/root/.ssh/id_rsa_SVC': " { send
-- "passphrase\r" }
-re "Enter passphrase for RSA key '.*': " { send -- "passphrase.\r"
}
-re "..*" { send_error -- "$expect_out(0,string)" }
}

expect -re "^\r\n"

close_on_eof 0
interact
expect
exit
##########

The command line invocation is

echo "{command1}
{command2}
exit" | expect -f {script}

where {command1} and {command2} are arbitrary commands and {script} is
of course the above Expect script.

Using the close_on_eof / interact / expect sequence as per the thread
http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/b75184d13782f114/f731162c65184d7a?lnk=gst&q=expect+pipe+input+interact&rnum=1#f731162c65184d7a
("using Expect as path in pipe"), above pipe hangs.

Using Expect's -d option to trigger debugging, the final part of the
trace was (I've explicitly inserted linefeeds after the \r\n sequences
to hopefully render it a bit clearer):

expect: does "\r\n" (spawn_id exp6) match regular expression "^\r\n"?
yes
expect: set expect_out(0,string) "\r\n"
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\r\n"
spawn id exp0 sent <svcinfo lsnode\nsvcinfo lsnode\nexit\n>
interact: received eof from spawn_id exp0
expect: read eof
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "{command1}\r\n
{command2}\r\n
exit\r\n
Last login: Wed Sep 27 17:20:34 2006 from 10.2.82.100\r\r\n
{command1}\r\n
{command2}\r\n
exit\r\n
IBM_2145:DES_SVC1:admin>{command1}\r\n
{output from command1}\r\n
IBM_2145:DES_SVC1:admin>{command2}\r\n
{output from command2}\r\n
IBM_2145:DES_SVC1:admin>exit\r\n
exit\r\n
Connection to dessvc closed.\r\r\n"
write() failed to write anything - will sleep(1) and retry...


Seeing that the output was apparently being received into
expect_out(buffer), I then thought that send_user could dump the
output, so I recast the final part of the Expect script thusly:

....
close_on_eof 0
interact
expect
send_user -- "$expect_out(buffer)"
exit


But, no dice, the final part of the debug trace was:

send: spawn id exp0 not open
while executing
"send_user -- "$expect_out(buffer)""
(file "z" line 24)
write() failed to write anything - will sleep(1) and retry...


send_tty worked though:

....
close_on_eof 0
interact
expect
send_tty -- "$expect_out(buffer)"
exit


The output now appeared as:

svcinfo lsnode
svcinfo lsnode
exit
Last login: Wed Sep 27 17:34:18 2006 from 10.2.82.100
svcinfo lsnode
svcinfo lsnode
exit
IBM_2145:DES_SVC1:admin>{command1}
{output from command1}
IBM_2145:DES_SVC1:admin>{command2}
{output from command2}
exit
Connection to dessvc closed.


However:

1. send_tty of course sends its output to the session terminal, not to
stdout as such. I'd like to know why send_user didn't do that.

2. Even the output as produced by send_tty included extraneous stuff
like the input commands and prompt strings. Ideally I would have like
just the outputs, in this case the {output from command1} and {output
from command2} sections. Is this possible?

3. The close_on_eof setting was not advertised in the Expect manpage.
Indeed it announces a date of 29 December 1994, perhaps it needs an
update.


Thanks for any help.

From: Bezoar on

howardbryden(a)compuserve.com wrote:
> I'm attempting to pipe commands to ssh(1) while also using Expect to
> handle the optional dialog that ssh can generate. I'm using version
> 5.43.0 under HP-UX 11.11.
>
> My Expect script is as follows:
>
> ##########
> if [catch "spawn -noecho /usr/bin/ssh -i ~/.ssh/id_rsa_SVC -l admin
> dessvc" reason] {
> send_error -- "x: Failed to spawn SSH: $reason\n"
> exit 1
> }
>
> set timeout -1
> log_user 0
>
> expect {
> -exact "Are you sure you want to continue connecting (yes/no)? " {
> send -- "yes\r"; exp_continue }
> -exact "yes\r\n" exp_continue
> -re "Warning: Permanently added '.*' (.*) to the list of known
> hosts.\r\r\n" exp_continue
> -exact "Enter passphrase for key '/root/.ssh/id_rsa_SVC': " { send
> -- "passphrase\r" }
> -re "Enter passphrase for RSA key '.*': " { send -- "passphrase.\r"
> }
> -re "..*" { send_error -- "$expect_out(0,string)" }
> }
>
> expect -re "^\r\n"
>
> close_on_eof 0
> interact
> expect
> exit
> ##########
>
> The command line invocation is
>
> echo "{command1}
> {command2}
> exit" | expect -f {script}
>
> where {command1} and {command2} are arbitrary commands and {script} is
> of course the above Expect script.
>
> Using the close_on_eof / interact / expect sequence as per the thread
> http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/b75184d13782f114/f731162c65184d7a?lnk=gst&q=expect+pipe+input+interact&rnum=1#f731162c65184d7a
> ("using Expect as path in pipe"), above pipe hangs.
>
> Using Expect's -d option to trigger debugging, the final part of the
> trace was (I've explicitly inserted linefeeds after the \r\n sequences
> to hopefully render it a bit clearer):
>
> expect: does "\r\n" (spawn_id exp6) match regular expression "^\r\n"?
> yes
> expect: set expect_out(0,string) "\r\n"
> expect: set expect_out(spawn_id) "exp6"
> expect: set expect_out(buffer) "\r\n"
> spawn id exp0 sent <svcinfo lsnode\nsvcinfo lsnode\nexit\n>
> interact: received eof from spawn_id exp0
> expect: read eof
> expect: set expect_out(spawn_id) "exp6"
> expect: set expect_out(buffer) "{command1}\r\n
> {command2}\r\n
> exit\r\n
> Last login: Wed Sep 27 17:20:34 2006 from 10.2.82.100\r\r\n
> {command1}\r\n
> {command2}\r\n
> exit\r\n
> IBM_2145:DES_SVC1:admin>{command1}\r\n
> {output from command1}\r\n
> IBM_2145:DES_SVC1:admin>{command2}\r\n
> {output from command2}\r\n
> IBM_2145:DES_SVC1:admin>exit\r\n
> exit\r\n
> Connection to dessvc closed.\r\r\n"
> write() failed to write anything - will sleep(1) and retry...
>
>
> Seeing that the output was apparently being received into
> expect_out(buffer), I then thought that send_user could dump the
> output, so I recast the final part of the Expect script thusly:
>
> ...
> close_on_eof 0
> interact
> expect
> send_user -- "$expect_out(buffer)"
> exit
>
>
> But, no dice, the final part of the debug trace was:
>
> send: spawn id exp0 not open
> while executing
> "send_user -- "$expect_out(buffer)""
> (file "z" line 24)
> write() failed to write anything - will sleep(1) and retry...
>
>
> send_tty worked though:
>
> ...
> close_on_eof 0
> interact
> expect
> send_tty -- "$expect_out(buffer)"
> exit
>
>
> The output now appeared as:
>
> svcinfo lsnode
> svcinfo lsnode
> exit
> Last login: Wed Sep 27 17:34:18 2006 from 10.2.82.100
> svcinfo lsnode
> svcinfo lsnode
> exit
> IBM_2145:DES_SVC1:admin>{command1}
> {output from command1}
> IBM_2145:DES_SVC1:admin>{command2}
> {output from command2}
> exit
> Connection to dessvc closed.
>
>
> However:
>
> 1. send_tty of course sends its output to the session terminal, not to
> stdout as such. I'd like to know why send_user didn't do that.
>
> 2. Even the output as produced by send_tty included extraneous stuff
> like the input commands and prompt strings. Ideally I would have like
> just the outputs, in this case the {output from command1} and {output
> from command2} sections. Is this possible?
>
> 3. The close_on_eof setting was not advertised in the Expect manpage.
> Indeed it announces a date of 29 December 1994, perhaps it needs an
> update.
>
>
> Thanks for any help.

try piping your commands to a shell executed by ssh like so
put in your own values for user, host, password,
I changed the expect part to test but you can modify the actual ssh
options
and expect text string to your requirements.
#!/opt/usr/bin/tclsh8.4
package require Expect
# read in input
set buff [read stdin ]
if [catch {spawn /usr/bin/ssh -i ~/.ssh/id_dsa.pub $user@$host
"/bin/sh" } reason] {
send_user -- "x: Failed to spawn SSH: $reason\n"
exit 1
}
set timeout -1
log_user 0

expect {
-re ".*password:" {
exp_send "$password\r"
exp_continue;
}
-re ".* (yes/no)? " {
send -- "yes\r"; {
exp_continue
}
-re ".*Warning: Permanently .*known hosts.\r\r\n" exp_continue
}
-re "..*" { send_error -- "$expect_out(0,string)" }
}

exp_send "$buff\r"
expect {
eof {
puts "$expect_out(buffer)"
}
}
catch { exp_close -i $spawn_id }
# comment this out to just get output from your command
puts " [ exp_wait -i $spawn_id -nowait ]"

suppose above is in fiel expectpipe.tcl then
echo "ls -la /tmp; exit " | expectpipe.tcl
would give you :
drwxrwxrwt 34 root root 69632 Sep 27 12:23 .
drwxr-xr-x 30 root root 4096 Sep 13 10:42 ..
...
12989 exp4 0 0

From: howardbryden on

Bezoar wrote:
> I changed the expect part to test but you can modify the actual ssh options and expect text string to your requirements.
> ...
> exp_send "$buff\r"
> expect {
> eof {
> puts "$expect_out(buffer)"
> }
> }
....

Unfortunately the target host (an IBM SVC) apparently offered only a
restricted shell and so I could not run /bin/sh.

I found that exp_send hung but if I recast this section to

expect {
-re "{promptstring}" { send "$buff\r" }
}

expect {
eof { puts "$expect_out(buffer)" }
}

(where {promptstring} is the prompt issued by the program), then I get
the output. There's still the problem of separating the output from
echoed command strings and other stuff, but that's a more manageable
problem.

Thanks.