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

2024-05-15 22:35:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我想从python运行一个shell命令,并使用子流程.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


Tags: intestmostreadoutputstdoutlinecall
2条回答

@pythonm已经解释了NameError。在

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

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

如果您想实时监视子进程的输出,那么communicate()是错误的方法。运行子进程,监视它(例如在一个循环中),并与其Popen.stdoutPopen.stderr属性(它们那时是类似文件的对象)交互。@mgilson的回答向您展示了一种方法:)

这里的问题是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). 

相关问题 更多 >