你能像往常一样制作python子进程输出stdout和stderr,还能将输出捕获为字符串吗?

pfl*_*rre 30 python subprocess

可能重复:
包装子进程'stdout/stderr

这个问题中,hanan-n询问是否可以将python子进程输出到stdout,同时还将输出保存在字符串中以便以后处理.在这种情况下,解决方案是遍历每个输出行并手动打印它们:

output = []
p = subprocess.Popen(["the", "command"], stdout=subprocess.PIPE)
for line in iter(p.stdout.readline, ''):
    print(line)
    output.append(line)
Run Code Online (Sandbox Code Playgroud)

但是,此解决方案并未概括为您要为stdout和stderr执行此操作的情况,同时满足以下条件:

  • stdout/stderr的输出应分别转到父进程'stdout/stderr
  • 输出应该尽可能实时完成(但我最后只需要访问字符串)
  • stdout和stderr行之间的顺序不应该改变(我不太确定如果子进程以不同的时间间隔刷新它的stdout和stderr缓存,那怎么会工作;我们现在假设我们得到的所有东西都是包含完整的好块行?)

我查看了子进程文档,但找不到任何可以实现此目的的东西.我能找到的最接近的是添加stderr=subprocess.stdout和使用与上面相同的解决方案,但是我们失去了常规输出和错误之间的区别.有任何想法吗?我猜测解决方案 - 如果有的话 - 将涉及异步读取p.stdoutp.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]
Run Code Online (Sandbox Code Playgroud)

Tho*_*ele 35

这个例子似乎对我有用:

# -*- 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)
Run Code Online (Sandbox Code Playgroud)

一般情况下,如果你想同时使用多个文件描述符并且你不知道哪个会有东西供你阅读,你应该使用select或类似的东西(如Twisted reactor).

  • 它不适用于Windows.select()仅在Windows上接受套接字 (5认同)
  • 这个答案有问题.如果在调用select()和调用poll()之间的流中有更多数据可读,则永远不会打印该数据. (3认同)
  • 它大部分时间都可以工作,但我注意到有时甚至当`p.poll()为None`时,并不是所有的stdout/stderr内容都被写入屏幕.我在proc.stdout/stderr.readlines()中添加了类似`for line的内容:print(line)`,就在休息之前,它似乎有效. (2认同)
  • 警告!readline() 被阻塞。这个例子提供了一个很好的开始想法,但它还不完整,无法在生产中使用。请在此处查看更完整的 Adam Rosenfeld 版本:http://stackoverflow.com/questions/7729336/how-can-i-print-and-display-subprocess-stdout-and-stderr-output-without- Distori/7730201#7730201 (2认同)

jfs*_*jfs 9

要以可移植的方式打印到控制台并在子进程的字符串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()
Run Code Online (Sandbox Code Playgroud)

teed_call()Python子进程中定义的地方将子输出到文件和终端?

您可以使用任何类似文件的对象(.write()方法).

  • 这不起作用,至少并非总是如此:`AttributeError:StringIO实例没有属性'fileno' (7认同)
  • @KomodoDave:您确定使用提供的链接中定义的[`teed_call()`](http://stackoverflow.com/a/4985080/4279)并且*不是*`subprocess.call()`?我已将 `call()` 重命名为 `teed_call()` 以避免混淆(以防万一)。 (2认同)
  • @KomodoDave 你能删除你的误导性评论吗?该代码确实有效。 (2认同)