使用子进程时如何在 Python 中复制 tee 行为?

新手上路,请多包涵

我正在寻找一个 Python 解决方案,它允许我将命令的输出保存在一个文件中,而不会将其隐藏在控制台中。

仅供参考:我问的是 tee (作为 Unix 命令行实用程序),而不是 Python intertools 模块中具有相同名称的函数。

细节

  • Python解决方案(不调用 tee ,Windows下不可用)
  • 我不需要为被调用的进程向标准输入提供任何输入
  • 我无法控制被调用的程序。我所知道的是它会向 stdout 和 stderr 输出一些东西并返回一个退出代码。
  • 在调用外部程序(子进程)时工作
  • stderrstdout 工作
  • 能够区分 stdout 和 stderr,因为我可能只想向控制台显示其中一个,或者我可以尝试使用不同的颜色输出 stderr - 这意味着 stderr = subprocess.STDOUT 将不起作用。
  • 实时输出(渐进式)- 该过程可以运行很长时间,我无法等待它完成。
  • Python 3 兼容代码(重要)

参考

以下是我目前发现的一些不完整的解决方案:

图 http://blog.i18n.ro/wp-content/uploads/2010/06/Drawing_tee_py.png

当前代码(第二次尝试)

 #!/usr/bin/python
from __future__ import print_function

import sys, os, time, subprocess, io, threading
cmd = "python -E test_output.py"

from threading import Thread
class StreamThread ( Thread ):
    def __init__(self, buffer):
        Thread.__init__(self)
        self.buffer = buffer
    def run ( self ):
        while 1:
            line = self.buffer.readline()
            print(line,end="")
            sys.stdout.flush()
            if line == '':
                break

proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutThread = StreamThread(io.TextIOWrapper(proc.stdout))
stderrThread = StreamThread(io.TextIOWrapper(proc.stderr))
stdoutThread.start()
stderrThread.start()
proc.communicate()
stdoutThread.join()
stderrThread.join()

print("--done--")

#### test_output.py ####

#!/usr/bin/python
from __future__ import print_function
import sys, os, time

for i in range(0, 10):
    if i%2:
        print("stderr %s" % i, file=sys.stderr)
    else:
        print("stdout %s" % i, file=sys.stdout)
    time.sleep(0.1)

实际输出

stderr 1
stdout 0
stderr 3
stdout 2
stderr 5
stdout 4
stderr 7
stdout 6
stderr 9
stdout 8
--done--

预期的输出是对行进行排序。注意,修改 Popen 以仅使用一个 PIPE 是不允许的,因为在现实生活中我想用 stderr 和 stdout 做不同的事情。

同样,即使在第二种情况下,我也无法获得实时的结果,实际上所有结果都是在过程完成时收到的。默认情况下,Popen 不应使用缓冲区 (bufsize=0)。

原文由 sorin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 668
1 个回答

我看到这是一个相当古老的帖子,但以防万一有人仍在寻找一种方法来做到这一点:

 proc = subprocess.Popen(["ping", "localhost"],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)

with open("logfile.txt", "w") as log_file:
  while proc.poll() is None:
     line = proc.stderr.readline()
     if line:
        print "err: " + line.strip()
        log_file.write(line)
     line = proc.stdout.readline()
     if line:
        print "out: " + line.strip()
        log_file.write(line)

原文由 Ben 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题