Я ищу решение Python, которое позволит мне сохранить вывод команды в файле, не скрывая ее от консоли.
FYI: Я спрашиваю о tee (как утилита командной строки Unix), а не о функции с тем же именем из Python intertools.
Подробнее
- Решение Python (не вызывающее
tee
, оно не доступно под Windows) - Мне не нужно предоставлять какие-либо данные для stdin для вызываемого процесса
- У меня нет контроля над вызываемой программой. Все, что я знаю, это вывод чего-то в stdout и stderr и возврат с кодом выхода.
- Работа при вызове внешних программ (подпроцесс)
- Чтобы работать как для
stderr
, так иstdout
- Возможность различать stdout и stderr, потому что я могу отображать только одну из них в консоли, или я мог бы попытаться вывести stderr с использованием другого цвета - это означает, что
stderr = subprocess.STDOUT
не будет работать. - Live output (progressive) - процесс может работать в течение длительного времени, и я не могу дождаться его завершения.
- Python 3 совместимый код (важно)
Ссылки
Вот некоторые неполные решения, которые я нашел до сих пор:
- http://devlishgenius.blogspot.com/2008/10/logging-in-real-time-in-python.html (mkfifo работает только в Unix)
- http://blog.kagesenshi.org/2008/02/teeing-python-subprocesspopen-output.html (не работает вообще)
Диаграмма 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).