如何从subprocess获取“实时”信息。python(2.5)

我想以下面的方式使用subprocess模块:

  1. 创build一个可能需要很长时间执行的新进程。
  2. 捕获stdout (或stderr ,或潜在的两个,一起或分开)
  3. 处理来自subprocess的数据也许是在接收到的每一行上触发事件(在wxPython中说)或者直接打印出来。

我用Popen创build了进程,但是如果使用通讯(),那么一旦进程终止,数据就会一次全部到达我。

如果我创build一个单独的线程,执行阻塞readline() myprocess.stdout (使用stdout = subprocess.PIPE myprocess.stdout ),我也没有得到这个方法的任何行,直到进程终止。 (不pipe我设定为bufsize)

有没有办法处理这个不可怕的,并在多个平台上运行良好?

更新代码似乎不工作(在Windows上)

 class ThreadWorker(threading.Thread): def __init__(self, callable, *args, **kwargs): super(ThreadWorker, self).__init__() self.callable = callable self.args = args self.kwargs = kwargs self.setDaemon(True) def run(self): try: self.callable(*self.args, **self.kwargs) except wx.PyDeadObjectError: pass except Exception, e: print e if __name__ == "__main__": import os from subprocess import Popen, PIPE def worker(pipe): while True: line = pipe.readline() if line == '': break else: print line proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) stdout_worker = ThreadWorker(worker, proc.stdout) stderr_worker = ThreadWorker(worker, proc.stderr) stdout_worker.start() stderr_worker.start() while True: pass 

标准输出将被缓冲 – 所以你不会得到任何东西,直到该缓冲区被填充,或subprocess退出。

您可以尝试从subprocess中刷新stdout ,或者使用stderr,或者在非缓冲模式下更改stdout。

听起来像这个问题可能是由subprocess使用缓冲输出 – 如果创build的输出相对较less,则可以在subprocess退出之前进行缓冲。 一些背景可以在这里find:

以下是对我有用的东西:

 cmd = ["./tester_script.bash"] p = subprocess.Popen( cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) while p.poll() is None: out = p.stdout.readline() do_something_with( out, err ) 

在你的情况下,你可以尝试将引用传递给你的工作线程,并在线程内进行轮询。 我不知道当两个线程轮询(并与之交互)相同的subprocess时它将如何工作,但它可能工作。

另外请注意, while p.poll() is None:就是这样。 不要用while not p.poll()代替python 0 (成功终止的返回码)也被认为是False

我也遇到了这个问题。 出现问题是因为您正在尝试阅读stderr。 如果没有错误,则尝试从stderr读取将被阻止。

在Windows上,没有简单的方法来轮询()文件描述符(只有Winsock套接字)。

所以一个解决scheme是不要尝试从stderr读取。

使用非阻塞readlines的pexpect [ http://www.noah.org/wiki/Pexpect%5D将解决此问题。; 它源于pipe道被缓冲的事实,所以你的应用的输出被pipe道缓冲,因此在缓冲区填充或进程死亡之前,你不能到达那个输出。

这似乎是一个众所周知的Python限制,请参阅PEP 3145和其他人。

一次读取一个字符: http : //blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html

 import contextlib import subprocess # Unix, Windows and old Macintosh end-of-line newlines = ['\n', '\r\n', '\r'] def unbuffered(proc, stream='stdout'): stream = getattr(proc, stream) with contextlib.closing(stream): while True: out = [] last = stream.read(1) # Don't loop forever if last == '' and proc.poll() is not None: break while last not in newlines: # Don't loop forever if last == '' and proc.poll() is not None: break out.append(last) last = stream.read(1) out = ''.join(out) yield out def example(): cmd = ['ls', '-l', '/'] proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # Make all end-of-lines '\n' universal_newlines=True, ) for line in unbuffered(proc): print line example() 

我已经使用pexpect模块,这似乎工作正常。 http://sourceforge.net/projects/pexpect/

使用subprocess.Popen,我可以运行我的一个C#项目的.exe,并将输出redirect到我的Python文件。 我现在可以将输出到C#控制台的所有信息(使用Console.WriteLine()print() )到Python控制台。

Python代码:

 from subprocess import Popen, PIPE, STDOUT p = Popen('ConsoleDataImporter.exe', stdout = PIPE, stderr = STDOUT, shell = True) while True: line = p.stdout.readline() print(line) if not line: break 

这将得到我的.NET项目的控制台输出线,因为它是创build的,并在项目终止时摆脱封闭的while循环。 我想这也可以用于两个python文件。