一尘不染

您可以像往常一样使python子进程输出stdout和stderr,但也可以将输出捕获为字符串吗?

python

在这个问题中,hanan-n询问是否有可能有一个向stdout输出的python子进程,同时还将输出保留在字符串中以供以后处理。在这种情况下,解决方案是遍历每条输出线并手动打印它们:

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]

阅读 134

收藏
2020-12-20

共1个答案

一尘不染

这个例子似乎对我有用:

# -*- 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或等效方法(例如Twisted Reactor)。

2020-12-20