我正在使用Python的subprocess.communicate()
从运行大约一分钟的进程读取stdout。Python:读取来自subprocess.communicate()的流输入
如何以流方式打印出该进程的stdout的每一行,以便我可以在输出生成时看到输出,但在继续之前仍会阻止进程终止?
subprocess.communicate()
似乎一次给所有的输出。
我正在使用Python的subprocess.communicate()
从运行大约一分钟的进程读取stdout。Python:读取来自subprocess.communicate()的流输入
如何以流方式打印出该进程的stdout的每一行,以便我可以在输出生成时看到输出,但在继续之前仍会阻止进程终止?
subprocess.communicate()
似乎一次给所有的输出。
请注意,我认为J.F. Sebastian's method (below)更好。
下面是一个简单的例子(没有进行错误检查):
import subprocess
proc = subprocess.Popen('ls',
shell=True,
stdout=subprocess.PIPE,
)
while proc.poll() is None:
output = proc.stdout.readline()
print output,
如果ls
结束得太快,那么您已经阅读所有的数据之前,while循环可能会结束。
您可以赶上在标准输出余这样说:
output = proc.communicate()[0]
print output,
该方案是否成为python doc引用的缓冲区阻塞问题的受害者? – 2010-04-26 19:22:08
@海因里希,缓冲区阻塞问题不是我理解得很好。我相信(仅仅从google搜索),只有当你没有从while循环中读取stdout(和stderr?)时才会出现这个问题。所以我认为上面的代码是可以的,但我不能肯定地说。 – unutbu 2010-04-26 19:44:44
这实际上也从一个阻塞问题的困扰,几年前我没有结束麻烦,其中的readline将阻止,直到它得到了即使PROC结束了一个换行符。我不记得了解决方案,但我认为它有事情做与做读取一个工作线程,只是循环'而proc.poll()是无:time.sleep(0)'或诸如此类的话。基本上,您需要确保输出换行符是流程所做的最后一件事(因为您不能让解释器时间再次循环),或者您需要做一些“花哨”的事情。 – 2010-04-26 20:05:32
如果你想要一个非阻塞的方法,不要使用process.communicate()
。如果将subprocess.Popen()
参数stdout
设置为PIPE
,则可以从process.stdout
中读取并检查过程是否仍使用process.poll()
运行。
[非阻塞方法不是直接的(http://stackoverflow.com/q/375427/4279) – jfs 2015-09-23 14:45:34
我相信从以流方式的过程收集输出最简单的方法是这样的:
import sys
from subprocess import *
proc = Popen('ls', shell=True, stdout=PIPE)
while True:
data = proc.stdout.readline() # Alternatively proc.stdout.read(1024)
if len(data) == 0:
break
sys.stdout.write(data) # sys.stdout.buffer.write(data) on Python 3.x
的readline()
或read()
函数应该只在EOF结束后返回一个空字符串,否则它将在没有任何内容需要读取时阻塞(readline()
包含换行符,所以在空行上,它返回“\ n”)。这避免了在循环之后需要一个尴尬的最终communicate()
调用。
对于具有很长行read()
的文件,可能更适合减少最大内存使用量 - 传递给它的数量是任意的,但排除它会导致一次读取整个管道输出,这可能不合需要。
'data = proc.stdout.read()'阻塞,直到读取所有*数据。你可能会把它与os.read(fd,maxsize)混淆起来,它可以提前返回(只要有数据可用)。 – jfs 2013-08-22 09:15:24
你是对的,我错了。但是,如果将合理数量的字节作为参数传递给'read()',那么它可以正常工作,并且只要最大行长度合理,'readline()'也可以正常工作。相应地更新我的答案。 – 2013-08-22 23:46:34
尽快子进程刷新其标准输出缓冲区获得由线子输出线:
#!/usr/bin/env python2
from subprocess import Popen, PIPE
p = Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1)
with p.stdout:
for line in iter(p.stdout.readline, b''):
print line,
p.wait() # wait for the subprocess to exit
iter()
来,尽快为他们写要解决the read-ahead bug in Python 2读线。
如果子进程的stdout在非交互模式下使用块缓冲而不是行缓冲(导致输出延迟,直到孩子的缓冲区已满或被孩子明确刷新),那么您可以尝试强制使用pexpect
, pty
modules或unbuffer
, stdbuf
, script
utilities无缓冲输出,见Q: Why not just use a pipe (popen())?
这里的Python 3中的代码:
#!/usr/bin/env python3
from subprocess import Popen, PIPE
with Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
print(line, end='')
注意:与输出子过程的Python 2字节串原样; Python 3使用文本模式(cmd的输出使用locale.getpreferredencoding(False)
编码进行解码)。
如果你只是想通过实时传递输出,很难得到比这更简单:
import subprocess
# This will raise a CalledProcessError if the program return a nonzero code.
# You can use call() instead if you don't care about that case.
subprocess.check_call(['ls', '-l'])
见docs for subprocess.check_call()。
如果你需要处理它的输出,当然,循环。但如果你不这样做,那就保持简单。
编辑:J.F. Sebastian指出二者,对于输出和错误参数的缺省值通过sys.stdout来和sys.stderr,那如果sys.stdout的和sys.stderr已被替换,这将失败(比如,用于在测试中捕获输出)。
如果将'sys.stdout'或'sys.stderr'替换为没有真正的fileno()的文件类对象,它将不起作用。如果'sys.stdout','sys.stderr'没有被替换,那么它更简单:'subprocess.check_call(args)'。 – jfs 2015-09-22 18:47:24
谢谢!我意识到替换sys.stdout/stderr的变幻莫测,但不知何故,如果你忽略参数,它会将stdout和stderr传递给正确的地方。除非我想要'CalledProcessError',否则我喜欢'call()'通过'check_call()'。 – Nate 2015-09-23 14:41:29
'python -mthis':*“错误不应该默默通过。” 除非明确声明为无效。“*这就是为什么_example code_应该比'call()'更适合'check_call()'的原因。 – jfs 2015-09-23 14:42:43
myCommand="ls -l"
cmd=myCommand.split()
# "universal newline support" This will cause to interpret \n, \r\n and \r equally, each as a newline.
p = subprocess.Popen(cmd, stderr=subprocess.PIPE, universal_newlines=True)
while True:
print(p.stderr.readline().rstrip('\r\n'))
解释你的解决方案只是为了让人们更好地理解,总是很好 – DaFois 2017-11-12 23:44:50
相关:[获取实时输出使用子过程](http://stackoverflow.com/q/803265/4279) – jfs 2014-10-16 20:11:54