2

我想从 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 这篇文章的启发:

从 python 中的 xinput 测试中读取标准输出

4

2 回答 2

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). 
于 2012-09-14T12:24:43.563 回答
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 的回答向您展示了一种方法:)

于 2012-09-14T12:24:58.320 回答