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

Python Popen:如何终止子流程并接收其输出?,python,subprocess,stdout,Python,Subprocess,Stdout,我想从python运行一个shell命令,并通过subprocess.Popen接收其输出。问题是,当我关闭进程并发送Ctrl-C时,我没有得到任何输出。我做错了什么?代码: >>> import subprocess >>> sub = subprocess.Popen(["xinput", "test", "8"], stdout=subprocess.PIPE) #receive mouse events >>> output = su

我想从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
导入子流程 >>>sub=subprocess.Popen([“xinput”、“test”、“8”],stdout=subprocess.PIPE)#接收鼠标事件 >>>输出=sub.communicate()[0]。读取() ^CTraceback(最近一次通话最后一次): 文件“”,第1行,在 文件“/usr/lib/python2.6/subprocess.py”,第693行 stdout=self.stdout.read() 键盘中断 >>>输出 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 NameError:未定义名称“输出” 受Jett这篇文章的启发:


这里的问题是在调用
通信时发送
键盘中断。因此,
communicate
永远不会返回,因此它的输出永远不会存储在变量
output
中,当您尝试使用它时,您会得到
namererror
。一种解决办法是:

 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). 

@pythonm已经解释了
名称错误

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

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


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

所发生的事情是,您执行一个python语句,然后通过ctrl+C从命令行终止它,这意味着输出不会被分配,因为引发了异常,因此输出不会被分配,您会得到NameError。通过kill或其他方式关闭进程,而不终止python语句else@pythonm--或者通过任何异常终止它。@Bob,xinput需要记住的一件事是,如果您开始从测试中读取数据,它将被缓冲,因此您将只得到数据的一小部分,这是一个可能的解决方案,因为假装TTY似乎需要实时输出。@jett谢谢,但我不确定,我理解,当谈到缓冲时,你的意思是什么。谁缓冲数据?为什么我只能得到数据的一小部分?我为什么要伪造一个TTY?您建议使用
pexpect
module?-Bob
xinput test
似乎只在连接到TTY时实时输出数据,否则它会将其输出存储到缓冲区中,并在缓冲区填满后输出。以下是对进一步信息的回复。谢谢,简·菲利普。“subprocess”作者将“communicate”stdout/stderr/stdin的参数和输出命名为str,这是一个相当欺骗性的想法,尽管它们实际上是str的。像我这样不耐烦的读者会被抓住。:)谢谢,我知道了。不再在一行中混合复杂的操作。