我的 python 脚本使用 subprocess 来调用一个非常嘈杂的 linux 实用程序。我想将所有输出存储到一个日志文件中,并将其中的一些显示给用户。我认为以下内容会起作用,但直到该实用程序生成大量输出后,输出才会显示在我的应用程序中。
#fake_utility.py, just generates lots of output over time
import time
i = 0
while True:
print hex(i)*512
i += 1
time.sleep(0.5)
#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
for line in proc.stdout:
#the real code does filtering here
print "test:", line.rstrip()
我真正想要的行为是让过滤器脚本打印从子进程接收到的每一行。有点像 tee
所做的,但使用 python 代码。
我错过了什么?这可能吗?
更新:
如果将 sys.stdout.flush()
添加到 fake_utility.py,则代码在 python 3.1 中具有所需的行为。我正在使用 python 2.6。你会认为使用 proc.stdout.xreadlines()
会像 py3k 一样工作,但事实并非如此。
更新 2:
这是最小的工作代码。
#fake_utility.py, just generates lots of output over time
import sys, time
for i in range(10):
print i
sys.stdout.flush()
time.sleep(0.5)
#display out put line by line
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
#works in python 3.0+
#for line in proc.stdout:
for line in iter(proc.stdout.readline,''):
print line.rstrip()
原文由 deft_code 发布,翻译遵循 CC BY-SA 4.0 许可协议
我认为问题在于语句
for line in proc.stdout
,它在迭代之前读取整个输入。解决方案是使用readline()
代替:当然,您仍然必须处理子进程的缓冲。
注意: 根据文档,使用迭代器的解决方案应该等同于使用
readline()
,除了预读缓冲区,但是(或正因为如此)建议的更改确实为我产生了不同的结果( Windows XP 上的 Python 2.5)。