Tee'ing Python subprocess.Popen output

A little hack for python coders out there who wanted to have a functionality similar to the unix's tee command for redirecting output to multiple places.

import sys
from subprocess import Popen,PIPE
p = Popen(['put','command','and','arguments','here'],stdout=PIPE)

while True:
o = p.stdout.readline()
if o == '' and p.poll() != None: break
# the 'o' variable stores a line from the command's stdout
# do anything u wish with the 'o' variable here
# this loop will break once theres a blank output
# from stdout and the subprocess have ended


Andrew Z said…
Just what I was looking for! BTW, I use Fedora too. :)
miya said…
This comment has been removed by the author.
miya said…
But... isn't the Popen command a sync. one ?
I mean, the while loop will only get executed once the Popen finishes...
Is this a feature or a bug ?
Unknown said…
subprocess.Popen is async, command executed in subprocess.Popen will go to background.

The while loop, yeah, it'll only break after the command is done. If u want to make it async (for GUI use for example) u should think of another way, perhaps printing the output out through GTK callback or something.
miya said…
Is it async?
I've been playing with this and there's sth. I just cannot figure out.

When I execute the following code, the main.py will only get into the p.poll() once the process finishes. It will stay blocked in the p.poll() line...

[code main.py]
import subprocess
import sys

def main():

p = subprocess.Popen(['python', 'test.py'], stdout = subprocess.PIPE)

while 1:
o = p.stdout.readline()
if o == '' and p.poll() != None:
print 'here!!!'
print o

if __name__ == "__main__":

and the test.py is

[code test.py]
import time

i = 0

while i != 5:
print "%s seconds" % i
i += 1


Anyway... thanx for answering =D
Unknown said…
thats weird,

replacing ['python','test.py'] with ['ping','www.google.com'] works.

for ['python','test.py'], o.stdout.readline() seems to wait for something. No idea why. Sorry, couldnt help much here.
miya said…
It's ok. Thanks for taking the time to answer.

Anonymous said…
This is the code I ended up using. It includes killing the process on interrupt, as well as flushing the output in opportune moments, such that the display isn't distorted. The app I was tee'ing is mplayer. Also take a look at the excellent pexpect package if you're more frequently confronted with the subject!

import signal,os
p = Popen(args,stdout=PIPE)
def kill(bla,blo): os.kill(p.pid,9)

while True:
____o = p.stdout.read(50)
____if o == '' and p.poll() != None: break
____f1 = o.rfind('\r')
____f2 = o.rfind('\n')
____if f1>=0 and (f2<0 or f2<f1):
____elif f2>=0:
Unknown said…
This comment has been removed by the author.
Unknown said…
The above solutions are not working and I added a question on stackoverflow, maybe we'll be able to find a generic solution for this issue.

Popular posts from this blog

Announcing PlatoCDP, a Plone distribution for enterprises.

Adding simple popup to Plone frontpage

Consolidated community site infrastructure on Plone