Python - 捕获 Popen stdout 并在控制台上显示?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1283061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python - capture Popen stdout AND display on console?
提问by Steve Folly
I want to capture stdout from a long-ish running process started via subprocess.Popen(...)
so I'm using stdout=PIPE
as an arg.
我想从一个长期运行的进程中捕获标准输出,subprocess.Popen(...)
因此我将其stdout=PIPE
用作参数。
However, because it's a long running process I also want to send the output to the console (as if I hadn't piped it) to give the user of the script an idea that it's still working.
但是,因为这是一个长时间运行的过程,我还想将输出发送到控制台(好像我没有通过管道传输它),让脚本的用户知道它仍在工作。
Is this at all possible?
这是可能吗?
Cheers.
干杯。
采纳答案by RichieHindle
Can you simply print
it as you read it from the pipe?
你能简单地print
从管道中读取它吗?
回答by Alex Martelli
The buffering your long-running sub-process is probably performing will make your console output jerky and very bad UX. I suggest you consider instead using pexpect(or, on Windows, wexpect) to defeat such buffering and get smooth, regular output from the sub-process. For example (on just about any unix-y system, after installing pexpect):
对长时间运行的子进程进行缓冲可能会使您的控制台输出不稳定并且用户体验非常糟糕。我建议你考虑使用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'
The ba and bu will come with the proper timing (about a second between them). Note the output is not subject to normal terminal processing, so the carriage returns are left in there -- you'll need to post-process the string yourself (just a simple .replace
!-) if you need \n
as end-of-line markers (the lack of processing is important just in case the sub-process is writing binary data to its stdout -- this ensures all the data's left intact!-).
ba 和 bu 将在适当的时间出现(它们之间大约一秒钟)。请注意,输出不受正常终端处理的影响,因此回车留在那里 -.replace
如果您需要\n
作为行尾标记(缺少处理很重要,以防子进程将二进制数据写入其标准输出——这可确保所有数据保持完整!-)。
回答by user135331
S. Lott's comment points to Getting realtime output using subprocessand Real-time intercepting of stdout from another process in Python
S. Lott 的评论指出使用子进程获取实时输出和实时拦截来自 Python 中另一个进程的标准输出
I'm curious that Alex's answer here is different from his answer 1085071. My simple little experiments with the answers in the two other referenced questions has given good results...
我很好奇亚历克斯在这里的答案与他的答案 1085071 不同。我对其他两个参考问题中的答案进行的简单小实验得到了很好的结果......
I went and looked at wexpect as per Alex's answer above, but I have to say reading the comments in the code I was not left a very good feeling about using it.
我按照上面 Alex 的回答查看了 wexpect,但我不得不说,阅读代码中的注释后,我对使用它的感觉并不好。
I guess the meta-question here is when will pexpect/wexpect be one of the Included Batteries?
我猜这里的元问题是 pexpect/wexpect 什么时候会成为包含的电池之一?
回答by maximk
Inspired by pty.openpty() suggestion somewhere above, tested on python2.6, linux. Publishing since it took a while to make this working properly, w/o buffering...
受到上面某处 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
回答by AI0867
Alternatively, you can pipe your process into tee and capture only one of the streams.
Something along the lines of sh -c 'process interesting stuff' | tee /dev/stderr
.
或者,您可以将您的过程通过管道传输到 tee 并仅捕获其中一个流。类似的东西sh -c 'process interesting stuff' | tee /dev/stderr
。
Of course, this only works on Unix-like systems.
当然,这只适用于类 Unix 系统。