subprocess.Popen:如何终止子进程并接收其输出?

时间:2012-09-14 12:14:02

标签: python subprocess stdout

我想从python运行shell命令并使用subprocess.Popen接收其输出。问题是,当我关闭进程,发送Ctrl-C时,我没有得到任何输出。我究竟做错了什么?代码:

>>> import subprocess
>>> sub = subprocess.Popen(["xinput", "test", "8"], stdout=subprocess.PIPE) #receive mouse events
>>> output = sub.communicate()[0].read()
^CTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/subprocess.py", line 693, in communicate
    stdout = self.stdout.read()
KeyboardInterrupt
>>> output
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'output' is not defined

受Jett的这篇文章的启发:

Reading stdout from xinput test in python

2 个答案:

答案 0 :(得分:4)

此处的问题是KeyboardInterrupt在致电communicate期间发送。因此,communicate永远不会返回,因此它的输出永远不会存储在变量output中,并且当您尝试使用它时会得到NameError。一种解决方法如下:

 import subprocess
 sub = subprocess.Popen(["xinput", "test", "8"], stdout=subprocess.PIPE)
 lines = [] #Need someplace to store the data as it comes
 try:
    for line in sub.stdout: #read one line from standard out, store it in lines
        lines.append(line)
 except KeyboardInterrupt:  #keyboardInterrupt happened.  Stop process
    sub.terminate()
 finally:                   #Join our lines into a single buffer (like `communicate`)
    output = ''.join(lines)
    del lines               #clean `lines` out of our namespace (just because). 

答案 1 :(得分:2)

@pythonm已经解释了NameError

此外,您使用Popen.communicate()概念错误的输出。它返回一个2元组的字符串:(stdout, stderr)。它不会返回两个类似文件的对象。这就是为什么sub.communicate()[0].read()如果communicate()返回则会失败的原因。

在子进程返回之前,communicate()聚合了它的所有stdout和stderr(考虑到你向构造函数提供了stdout=subprocess.PIPEstderr=subprocess.PIPE)。只有在子进程终止后,您才能访问在子进程运行时期间收集的communicate()

如果您想实时监控子流程的输出,那么communicate()是错误的方法。运行子进程,监视它(例如在循环内)并与其Popen.stdoutPopen.stderr属性(然后是类文件对象)进行交互。 @ mgilson的答案向您展示了如何做到这一点:)