views:

768

answers:

5

I am trying to grab stdout from a subprocess,Popen call and although I am achieving this easily by doing:

cmd = subprocess.Popen('ls -l', shell=True, stdout=PIPE)
for line in cmd.stdout.readlines():
    print line

I would like to grab stdout in "real time". With the above method, PIPE is waiting to grab all the stdout and then it returns.

So for logging purposes, this doesn't meet my requirements (e.g. "see" what is going on while it happens).

Is there a way to get line by line, stdout while is running? Or is this a limitation of subprocess (having to wait until the PIPE closes).

EDIT If I switch readlines() for readline() I only get the last line of the stdout (not ideal):

In [75]: cmd = Popen('ls -l', shell=True, stdout=PIPE)
In [76]: for i in cmd.stdout.readline(): print i
....: 
t
o
t
a
l

1
0
4

Thanks!

A: 

The call to readlines is waiting for the process to exit. Replace this with a loop around cmd.stdout.readline() (note singular) and all should be well.

calmh
ths just returns the last line, not all the lines: for i in cmd.stdout.readline(): print i ....: t o t a l 1 0 4
alfredodeza
Yes, my bad. The correct answer is the one by Robert Pate above.
calmh
+2  A: 
cmd = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE)
for line in cmd.stdout:
    print line.rstrip("\n")
Roger Pate
Roger, this is still waiting for the process to end. The way I can confirm this is happening, is by running a longer process like a system update and passing the information to the log. All lines in a 10 second running process are printed/written to the log at the same time
alfredodeza
You're running into a buffer size problem; take my above code and change the command to `["find", "/"]` and you will see output before that process ends.
Roger Pate
+2  A: 

Drop the readlines() which is coalescing the output. Also you'll need to enforce line buffering since most commands will interally buffer output to a pipe. For details see: http://www.pixelbeat.org/programming/stdio_buffering/

pixelbeat
I went through the link but I am not clear how to enforce buffering in Python, would you be able to clarify?
alfredodeza
You enforce buffering on the command. tail -f line buffers by default. For grep, sed etc. you'll need to pass appropriate options to them. Note also the new stdbuf command which can apply line buffering to any command that uses stdio
pixelbeat
+2  A: 

To get output "in real time", subprocess is unsuitable because it can't defeat the other process's buffering strategies. That's the reason I always recommend, whenever such "real time" output grabbing is desired (quite a frequent question on stack overflow!), to use instead pexpect (everywhere but Windows -- on Windows, wexpect).

Alex Martelli
Expect's line buffering is a topic (recently) dear to my heart; would you mind having a look at my latest question?
Tobu
@Tobu, sure, had a look and answered (recommending pexpect again).
Alex Martelli
+2  A: 

Your interpreter is buffering. Add a call to sys.stdout.flush() after your print statement.

Jeff
AMAZING! thank you! this was IT!, I had already given up... this worked perfectly.THANKS AGAIN! woo hoo!
alfredodeza