views:

401

answers:

3

Is there a way to do multiple calls in the same "session" in Popen? For instance, can I make a call through it and then another one after it without having to concatenate the commands into one long string?

A: 

For instance, can I make a call through it and then another one after it without having to concatenate the commands into one long string?

Sounds like you're using shell=True. Don't, unless you need to. Instead use shell=False (the default) and pass in a command/arg list.

Is there a way to do multiple calls in the same "session" in Popen? For instance, can I make a call through it and then another one after it without having to concatenate the commands into one long string?

Any reason you can't just create two Popen instances and wait/communicate on each as necessary? That's the normal way to do it, if I understand you correctly.

Devin Jeanpierre
+2  A: 

You're not "making a call" when you use popen, you're running an executable and talking to it over stdin, stdout, and stderr. If the executable has some way of doing a "session" of work (for instance, by reading lines from stdin) then, yes, you can do it. Otherwise, you'll need to exec multiple times.

subprocess.Popen is (mostly) just a wrapper around execvp(3)

Justus
This one explains the actual concepts rather than giving a technically-correct alternative solution, which is always good.
Arafangion
@Arafangion: What would an "alternative solution" look like? I can't figure out what the question even is. The only answer is this one -- you've got the concept wrong.
S.Lott
A: 

Assuming you want to be able to run a shell and send it multiple commands (and read their output), it appears you can do something like this:

from subprocess import *
p = Popen(['/bin/sh'], shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE)

After which, e.g.,:

>>> p.stdin.write("cat /etc/motd\n")
>>> p.stdout.readline()
'Welcome to dev-linux.mongo.com.\n'

(Of course, you should check stderr too, or else ask Popen to merge it with stdout). One major problem with the above is that the stdin and stdout pipes are in blocking mode, so it's easy to get "stuck" waiting forever for output from the shell. Although I haven't tried it, there's a recipe at the ActiveState site that shows how to address this.

Update: after looking at the related questions/answers, it looks like it might be simpler to just use Python's built-in select module to see if there's data to read on stdout (you should also do the same for stderr, of course), e.g.:

>>> select.select([p.stdout], [], [], 0)
([<open file '<fdopen>', mode 'rb' at 0x10341690>], [], [])
Jacob Gabrielson
That's no different, really, than concatenating the commands (with a ';') in-between with shell=True. Which was as far as I could tell what the original poster was suggesting. And it's still bad unless shell features are needed, which has not been shown. There are safer alternatives.
Devin Jeanpierre
Possibly; it's unclear from the question. But if you want to act as a "proxy" between a real user and the shell (for some reason), or send commands periodically based on some event, etc, it might be useful to do this. E.g., the ActiveState recipe seems to have been inspired by a real use case.
Jacob Gabrielson
I agree completely, I just don't think the advice is necessarily good in this particular context. I suppose only the asker knows.
Devin Jeanpierre