Python Popen:同时写入标准输出和日志文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15535240/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python Popen: Write to stdout AND log file simultaneously
提问by imagineerThat
I am using Popen to call a shell script that is continuously writing its stdout and stderr to a log file. Is there any way to simultaneously output the log file continuously (to the screen), or alternatively, make the shell script write to both the log file and stdout at the same time?
我正在使用 Popen 调用一个 shell 脚本,该脚本不断将其 stdout 和 stderr 写入日志文件。有没有办法同时连续输出日志文件(到屏幕),或者让 shell 脚本同时写入日志文件和标准输出?
I basically want to do something like this in Python:
我基本上想在 Python 中做这样的事情:
cat file 2>&1 | tee -a logfile #"cat file" will be replaced with some script
Again, this pipes stderr/stdout together to tee, which writes it both to stdout and my logfile.
同样,这将 stderr/stdout 一起传输到 tee,它将它同时写入 stdout 和我的日志文件。
I know how to write stdout and stderr to a logfile in Python. Where I'm stuck is how to duplicate these back to the screen:
我知道如何在 Python 中将 stdout 和 stderr 写入日志文件。我遇到的问题是如何将这些复制回屏幕:
subprocess.Popen("cat file", shell=True, stdout=logfile, stderr=logfile)
Of course I could just do something like this, but is there any way to do this without tee and shell file descriptor redirection?:
当然我可以做这样的事情,但是有没有办法在没有 tee 和 shell 文件描述符重定向的情况下做到这一点?:
subprocess.Popen("cat file 2>&1 | tee -a logfile", shell=True)
采纳答案by tdelaney
You can use a pipe to read the data from the program's stdout and write it to all the places you want:
您可以使用管道从程序的标准输出中读取数据并将其写入您想要的所有位置:
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()
UPDATE
更新
In python 3, the universal_newlinesparameter controls how pipes are used. If False, pipe reads return bytesobjects and may need to be decoded (e.g., line.decode('utf-8')) to get a string. If True, python does the decode for you
在 python 3 中,该universal_newlines参数控制管道的使用方式。如果False,管道读取返回bytes对象并且可能需要被解码(例如,line.decode('utf-8'))以获取字符串。如果True,python 为您进行解码
Changed in version 3.3: When universal_newlines is True, the class uses the encoding locale.getpreferredencoding(False) instead of locale.getpreferredencoding(). See the io.TextIOWrapper class for more information on this change.
在 3.3 版更改:当 Universal_newlines 为 True 时,该类使用编码 locale.getpreferredencoding(False) 而不是 locale.getpreferredencoding()。有关此更改的更多信息,请参阅 io.TextIOWrapper 类。
回答by jfs
To emulate: subprocess.call("command 2>&1 | tee -a logfile", shell=True)without invoking the teecommand:
模拟: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()
To fix possible buffering issues (if the output is delayed), see links in Python: read streaming input from subprocess.communicate().
要解决可能的缓冲问题(如果输出延迟),请参阅Python 中的链接:从 subprocess.communicate() 读取流输入。
Here's Python 3 version:
这是 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)

