[paramiko] How do I execute multiple commands in a single channel?

James rocketmonkeys at gmail.com
Mon Mar 30 07:55:20 PDT 2009


James B.,

> I would think about another approach. I've done a lot of remote
> administration, and there's usually a straight forward way to
> eliminate the need for interactivity.
>
> For your above example (just using ssh):
> $ ssh remote_host 'ls ~/folder'
> (look at output of command, see that "file_name" is there)
> $ ssh remote_host 'do_something_to file_name | another -command'

My thoughts on this are flip-flopping back and forth.  I'm thinking of
going back to exec_command() with a \n-delimited list of commands, and
just receive the results in total.  One caveat is that any commands
that rely on a shell being influenced by previous commands (like
changing the directory or setting environment vars) will have to be
redone each time, but the alternatives have problems as you've stated
below.  My goal in this is to have the client computer do all the
thinking, so that the server could be any bare server with SSH
installed.  Since this is a deployment & maintenance script, I am
trying to limit my dependencies on the remote side.

>> may be you can have a look at either Pexpect
>> http://pexpect.sourceforge.net/pexpect.html
>> (which is not currently using paramiko)
>
> Thanks Erik, I put off the 'expect like' problem for my second round ;)

Honestly, Pexpect is my first choice.  It has exactly the
functionality I want, but is unix-only.  If it weren't for that, I
wouldn't have even looked for paramiko (sorry devs!).  With a viable
cross-platform Pexpect for python MIA, then working with SSH directly
is my second option.

> James,
> The big issue with using an interactive shell, is that the output is
> meant for humans. So you then have to emulate a human reading the
> output stream in order to automate the commands. There's no signal to
> say that the command finished, so you're stuck using select.select()
> on the sockets (or channels in this case. You could also use
> recv_ready, and recv_stderr_ready), and then reading the output to
> look for clues that it's done.
>
> For example, if you 'ls ~/non_existent_file', and try to recv(),
> you're stuck blocking indefinitely, because the output is all on
> recv_stderr().

I've actually been thinking about this.  I tried the "cd
non_existent_file", and realized I had to read both the stderr and
stdout.  However, since they're both blocking, I need to check
recv_ready().  However, since that is false until data is received, I
really need to use some kind of select() type thing to check both.
And if I exec a couple of commands that have both stdout and stderr,
then it's even more complicated.  So I definitely agree, knowing when
a command has finished and what its output is is a problem here.

> If you send a long running command, that will continually send out
> data (like 'find / -name "*.so"') - how do you know when it's done?
> When you're at a terminal, you see your command prompt return, but
> here, that missing.
>
> -jim

In the normal bash, you'd get a prompt when it's done.  I'm assuming
when we run bash -s that's not the case.  Is there any other way to
determine end-of-command?  Looks like I'll have to stick with
exec_command() for now.  What I'm looking for is some hybrid... being
able to do "export ENVIRO=something" in one set of commands, know when
that command is done, and then execute more commands depending on
that.  Looks like this combination of features isn't available  yet.

That said, I'm so glad I found paramiko.  Even though it's not ideal
for my purposes, I can't wait to get my scripts up and running!
Thanks devs!

-James



More information about the paramiko mailing list