使用子进程时如何在 Python 中复制 tee 行为? [英] How to replicate tee behavior in Python when using subprocess?

查看:88
本文介绍了使用子进程时如何在 Python 中复制 tee 行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种 Python 解决方案,它可以让我将命令的输出保存在文件中,而无需将其隐藏在控制台中.

I'm looking for a Python solution that will allow me to save the output of a command in a file without hiding it from the console.

仅供参考:我在询问 tee(作为 Unix 命令行实用程序)而不是 Python intertools 模块中的同名函数.

FYI: I'm asking about tee (as the Unix command line utility) and not the function with the same name from Python intertools module.

  • Python 解决方案(不调用 tee,Windows 下不可用)
  • 我不需要为被调用进程的 stdin 提供任何输入
  • 我无法控制被调用的程序.我只知道它会向 stdout 和 stderr 输出一些东西,并返回一个退出代码.
  • 在调用外部程序(子进程)时工作
  • 同时适用于 stderrstdout
  • 能够区分 stdout 和 stderr,因为我可能只想向控制台显示其中之一,或者我可以尝试使用不同的颜色输出 stderr - 这意味着 stderr = subprocess.STDOUT 不会工作.
  • 实时输出(渐进式)- 进程可以运行很长时间,我不能等待它完成.
  • Python 3 兼容代码(重要)
  • Python solution (not calling tee, it is not available under Windows)
  • I do not need to provide any input to stdin for called process
  • I have no control over the called program. All I know is that it will output something to stdout and stderr and return with an exit code.
  • To work when calling external programs (subprocess)
  • To work for both stderr and stdout
  • Being able to differentiate between stdout and stderr because I may want to display only one of the to the console or I could try to output stderr using a different color - this means that stderr = subprocess.STDOUT will not work.
  • Live output (progressive) - the process can run for a long time, and I'm not able to wait for it to finish.
  • Python 3 compatible code (important)

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

Here are some incomplete solutions I found so far:

  • http://devlishgenius.blogspot.com/2008/10/logging-in-real-time-in-python.html (mkfifo works only on Unix)
  • http://blog.kagesenshi.org/2008/02/teeing-python-subprocesspopen-output.html (doesn't work at all)

图 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 做不同的事情.

Expected output was to have the lines ordered. Remark, modifying the Popen to use only one PIPE is not allowed because in the real life I will want to do different things with stderr and stdout.

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

Also even in the second case I was not able to obtain real-time like out, in fact all the results were received when the process finished. By default, Popen should use no buffers (bufsize=0).

推荐答案

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

I see that this is a rather old post but just in case someone is still searching for a way to do this:

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)

这篇关于使用子进程时如何在 Python 中复制 tee 行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆