我想从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的这篇文章的启发:
答案 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.PIPE
和stderr=subprocess.PIPE
)。只有在子进程终止后,您才能访问在子进程运行时期间收集的communicate()
。
如果您想实时监控子流程的输出,那么communicate()
是错误的方法。运行子进程,监视它(例如在循环内)并与其Popen.stdout
和Popen.stderr
属性(然后是类文件对象)进行交互。 @ mgilson的答案向您展示了如何做到这一点:)