繁体   English   中英

如何与 Popen 同时写入标准输出和日志文件?

[英]How to write to stdout AND to log file simultaneously with Popen?

我正在使用 Popen 调用一个 shell 脚本,该脚本不断将其 stdout 和 stderr 写入日志文件。 有没有办法同时连续输出日志文件(到屏幕),或者让 shell 脚本同时写入日志文件和标准输出?

我基本上想在 Python 中做这样的事情:

cat file 2>&1 | tee -a logfile #"cat file" will be replaced with some script

同样,这将 stderr/stdout 一起传输到 tee,它将它同时写入 stdout 和我的日志文件。

我知道如何在 Python 中将 stdout 和 stderr 写入日志文件。 我遇到的问题是如何将这些复制回屏幕:

subprocess.Popen("cat file", shell=True, stdout=logfile, stderr=logfile)

当然,我可以做这样的事情,但是有没有办法在没有 tee 和 shell 文件描述符重定向的情况下做到这一点?:

subprocess.Popen("cat file 2>&1 | tee -a logfile", shell=True)

您可以使用管道从程序的标准输出中读取数据并将其写入您想要的所有位置:

import sys
import subprocess

logfile = open('logfile', 'w')
proc=subprocess.Popen(['cat', 'file'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
    sys.stdout.write(line)
    logfile.write(line)
proc.wait()

更新

在 python 3 中, universal_newlines参数控制管道的使用方式。 如果为False ,管道读取返回bytes对象并且可能需要解码(例如, line.decode('utf-8') )以获取字符串。 如果为True ,python 会为您进行解码

在 3.3 版更改:当 Universal_newlines 为 True 时,该类使用编码 locale.getpreferredencoding(False) 而不是 locale.getpreferredencoding()。 有关此更改的更多信息,请参阅 io.TextIOWrapper 类。

模拟: subprocess.call("command 2>&1 | tee -a logfile", shell=True)不调用tee命令:

#!/usr/bin/env python2
from subprocess import Popen, PIPE, STDOUT

p = Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1)
with p.stdout, open('logfile', 'ab') as file:
    for line in iter(p.stdout.readline, b''):
        print line,  #NOTE: the comma prevents duplicate newlines (softspace hack)
        file.write(line)
p.wait()

要解决可能的缓冲问题(如果输出延迟),请参阅Python 中的链接:从 subprocess.communicate() 读取流输入

这是 Python 3 版本:

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, STDOUT

with Popen("command", stdout=PIPE, stderr=STDOUT, bufsize=1) as p, \
     open('logfile', 'ab') as file:
    for line in p.stdout: # b'\n'-separated lines
        sys.stdout.buffer.write(line) # pass bytes as is
        file.write(line)

为交互式应用程序逐字节写入终端

此方法立即将它获得的任何字节写入 stdout,这更接近地模拟tee的行为,尤其是对于交互式应用程序。

主文件

#!/usr/bin/env python3
import os
import subprocess
import sys
with subprocess.Popen(sys.argv[1:], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc, \
        open('logfile.txt', 'bw') as logfile:
    while True:
        byte = proc.stdout.read(1)
        if byte:
            sys.stdout.buffer.write(byte)
            sys.stdout.flush()
            logfile.write(byte)
            # logfile.flush()
        else:
            break
exit_status = proc.returncode

睡眠.py

#!/usr/bin/env python3
import sys
import time
for i in range(10):
    print(i)
    sys.stdout.flush()
    time.sleep(1)

首先,我们可以进行非交互式完整性检查:

./main.py ./sleep.py

我们看到它实时计数到标准输出。

接下来,对于交互式测试,您可以运行:

./main.py bash

然后,您键入的字符会在您键入时立即出现在终端上,这对于交互式应用程序非常重要。 这是运行时发生的情况:

bash | tee logfile.txt

此外,如果您希望输出立即显示在输出文件上,那么您还可以添加:

logfile.flush()

但是tee不这样做,我担心它会影响性能。 您可以使用以下方法轻松测试:

tail -f logfile.txt

相关问题: 子进程命令的实时输出

在 Ubuntu 18.04、Python 3.6.7 上测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM