【发布时间】:2010-11-19 23:06:59
【问题描述】:
我想从通过subprocess.Popen(...) 启动的长时间运行的进程中捕获标准输出,所以我使用stdout=PIPE 作为参数。
但是,因为这是一个长时间运行的过程,我还想将输出发送到控制台(好像我没有通过管道传输它一样),让脚本的用户知道它仍在工作。
这可能吗?
干杯。
【问题讨论】:
我想从通过subprocess.Popen(...) 启动的长时间运行的进程中捕获标准输出,所以我使用stdout=PIPE 作为参数。
但是,因为这是一个长时间运行的过程,我还想将输出发送到控制台(好像我没有通过管道传输它一样),让脚本的用户知道它仍在工作。
这可能吗?
干杯。
【问题讨论】:
或者,您可以将流程通过管道传输到 tee 并仅捕获其中一个流。
类似于sh -c 'process interesting stuff' | tee /dev/stderr。
当然,这只适用于类 Unix 系统。
【讨论】:
受上面某处 pty.openpty() 建议的启发,在 python2.6、linux 上测试。发布,因为它需要一段时间才能使其正常工作,没有缓冲......
def call_and_peek_output(cmd, shell=False):
import pty, subprocess
master, slave = pty.openpty()
p = subprocess.Popen(cmd, shell=shell, stdin=None, stdout=slave, close_fds=True)
os.close(slave)
line = ""
while True:
try:
ch = os.read(master, 1)
except OSError:
# We get this exception when the spawn process closes all references to the
# pty descriptor which we passed him to use for stdout
# (typically when it and its childs exit)
break
line += ch
sys.stdout.write(ch)
if ch == '\n':
yield line
line = ""
if line:
yield line
ret = p.wait()
if ret:
raise subprocess.CalledProcessError(ret, cmd)
for l in call_and_peek_output("ls /", shell=True):
pass
【讨论】:
S。洛特的评论指向Getting realtime output using subprocess和Real-time intercepting of stdout from another process in Python
我很好奇亚历克斯在这里的答案与他的答案 1085071 不同。 我对其他两个参考问题的答案进行了简单的小实验,结果很好......
按照上面 Alex 的回答,我去看了 wexpect,但我不得不说,阅读代码中的 cmets,我对使用它并没有很好的感觉。
我想这里的元问题是 pexpect/wexpect 什么时候会成为包含的电池之一?
【讨论】:
缓冲您的长时间运行的子进程可能会导致您的控制台输出不稳定和非常糟糕的用户体验。我建议您考虑改用pexpect(或者,在Windows 上,wexpect)来消除这种缓冲并从子进程中获得平滑、常规的输出。例如(在几乎任何 unix-y 系统上,安装 pexpect 之后):
>>> import pexpect
>>> child = pexpect.spawn('/bin/bash -c "echo ba; sleep 1; echo bu"', logfile=sys.stdout); x=child.expect(pexpect.EOF); child.close()
ba
bu
>>> child.before
'ba\r\nbu\r\n'
ba 和 bu 将在适当的时间出现(它们之间大约一秒钟)。请注意,输出不受正常终端处理的影响,因此回车符保留在那里 - 如果您需要 \n 作为结尾,您需要自己对字符串进行后处理(只是一个简单的.replace!-) -of-line 标记(缺少处理很重要,以防子进程将二进制数据写入其标准输出 - 这可确保所有数据完好无损!-)。
【讨论】:
当你从管道中读取它时,你能简单地 print 它吗?
【讨论】: