您可以像往常一样使python子流程输出stdout和stderr,但也可以将输出捕获为字符串吗?
可能重复:您可以像往常一样使python子流程输出stdout和stderr,但也可以将输出捕获为字符串吗?,python,subprocess,Python,Subprocess,可能重复: 在中,询问是否可能有一个python子进程输出到stdout,同时将输出保存在字符串中以供以后处理。这种情况下的解决方案是在每个输出行上循环并手动打印: output = [] p = subprocess.Popen(["the", "command"], stdout=subprocess.PIPE) for line in iter(p.stdout.readline, ''): print(line) output.append(line) 但是,此解决方
在中,询问是否可能有一个python子进程输出到stdout,同时将输出保存在字符串中以供以后处理。这种情况下的解决方案是在每个输出行上循环并手动打印:
output = []
p = subprocess.Popen(["the", "command"], stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
print(line)
output.append(line)
但是,此解决方案不适用于您希望同时对stdout和stderr执行此操作,同时满足以下条件的情况:
- stdout/stderr的输出应该分别转到父进程的stdout/stderr
- 输出应尽可能实时完成(但我只需要在最后访问字符串)
- stdout和stderr行之间的顺序不应该改变(如果子进程以不同的间隔刷新其stdout和stderr缓存,我不太确定这将如何工作;现在让我们假设所有内容都在包含完整行的好块中?)
stderr=subprocess.stdout
,并使用与上面相同的解决方案,但这样我们就失去了常规输出和错误之间的区别。有什么想法吗?我猜解决方案(如果有的话)将涉及对p.stdout
和p.stderr
进行异步读取
下面是我想做的一个例子:
p = subprocess.Popen(["the", "command"])
p.wait() # while p runs, the command's stdout and stderr should behave as usual
p_stdout = p.stdout.read() # unfortunately, this will return '' unless you use subprocess.PIPE
p_stderr = p.stderr.read() # ditto
[do something with p_stdout and p_stderr]
如上所述创建两个读卡器,一个用于
stdout
一个用于stderr
并在新线程中启动每个读卡器。这将以与流程输出的顺序大致相同的顺序追加到列表中。如果需要,请维护两个单独的列表
i、 e
这个例子似乎适合我:
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
import subprocess
import sys
import select
p = subprocess.Popen(["find", "/proc"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout = []
stderr = []
while True:
reads = [p.stdout.fileno(), p.stderr.fileno()]
ret = select.select(reads, [], [])
for fd in ret[0]:
if fd == p.stdout.fileno():
read = p.stdout.readline()
sys.stdout.write('stdout: ' + read)
stdout.append(read)
if fd == p.stderr.fileno():
read = p.stderr.readline()
sys.stderr.write('stderr: ' + read)
stderr.append(read)
if p.poll() != None:
break
print 'program ended'
print 'stdout:', "".join(stdout)
print 'stderr:', "".join(stderr)
一般来说,在任何情况下,如果您想同时使用多个文件描述符进行处理,但不知道哪一个文件描述符会有内容供您阅读,则应使用select或类似的工具(如扭曲反应器)。以可移植的方式打印到控制台并捕获子流程的字符串stdout/stderr:
from StringIO import StringIO
fout, ferr = StringIO(), StringIO()
exitcode = teed_call(["the", "command"], stdout=fout, stderr=ferr)
stdout = fout.getvalue()
stderr = ferr.getvalue()
其中teed\u call()
在中定义
您可以使用任何类似文件的对象(
.write()
方法)。我看不出这种技术(包装任何IO函数和流对象)如何不能通用化?您建议我如何让子进程实时打印到stdout和stderr,同时在最后以字符串形式获得输出,那么?用时间对线程排序是个坏主意。@Dani-这是两个截然不同的想法,时间一个不涉及线程…他们说你可以用wait()和poll()以及stdout(和stderr)的管道来实现死锁。顺序可能与原始顺序不完全相同,因为在调用select
时,stdout
和stderr
可能都有数据,但这与我目前看到的解决方案非常接近。非常感谢。虽然不太可能,但你是对的,你的情况有可能发生。但我不相信有可能保证这一点。请注意,通常stdout启用了行缓冲,而stderr没有。它在Windows上不起作用。select()仅在Windows上接受套接字此答案有问题。如果在调用select()和调用poll()之间的流中有更多的数据变得可读,那么这些数据将永远不会被打印出来。这种方法在大多数情况下都有效,但我注意到,有时即使p.poll()为None
,也不会将所有stdout/stderr内容都写入屏幕。我在proc.stdout/stderr.readlines()中为line添加了类似于的内容:在中断前打印(line)
,它似乎可以工作。Poster希望在stdout/stderr中输入数据时处理数据,而不是在命令末尾。@ThomasVanderStichele:单击链接并查看调用()
定义。它会尽快显示stdout/stderr。它不是subprocess.call()
。这不起作用,至少不总是这样:AttributeError:StringIO实例没有属性“fileno”
@KomodoDave:您确定使用了而不是subprocess.call()
?我已将call()
重命名为teed\u call()
,以避免混淆(以防万一)。@KomodoDave你能删除你的误导性评论吗?代码确实有效。
from StringIO import StringIO
fout, ferr = StringIO(), StringIO()
exitcode = teed_call(["the", "command"], stdout=fout, stderr=ferr)
stdout = fout.getvalue()
stderr = ferr.getvalue()