我正在使用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)
答案 0 :(得分:33)
您可以使用管道从程序的标准输出读取数据并将其写入您想要的所有位置:
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类。
答案 1 :(得分:13)
在不调用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: read streaming input from 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)
答案 2 :(得分:0)
为交互式应用程序逐字节写入终端
此方法将立即将所有写入到stdout的字节写到stdout,从而更紧密地模拟#!/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
的行为,尤其是对于交互式应用程序。
main.py
#!/usr/bin/env python3
import sys
import time
for i in range(10):
print(i)
sys.stdout.flush()
time.sleep(1)
sleep.py
./main.py ./sleep.py
首先,我们可以进行非交互式完整性检查:
./main.py bash
我们看到它实时计入标准输出。
接下来,要进行交互式测试,可以运行:
bash | tee logfile.txt
然后,您键入的字符会在您键入时立即显示在终端上,这对于交互式应用程序非常重要。这是您在运行时发生的情况:
logfile.flush()
此外,如果您希望输出立即显示在ouptut文件中,则还可以添加:
tee
但是tail -f logfile.txt
不能这样做,而且恐怕会降低性能。您可以使用以下方法轻松进行测试:
{{1}}
相关问题:live output from subprocess command
在Ubuntu 18.04,Python 3.6.7上进行了测试。