Отображение вывода подпроцесса в stdout и перенаправление его

Я запускаю скрипт через модуль подпроцесса Python. В настоящее время я использую:

p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = p.communicate() 

Затем я печатаю результат в stdout. Все это прекрасно, но по мере того, как сценарий занимает много времени, я хотел получить вывод в реальном времени из сценария в stdout. Причина, по которой я использую вывод, заключается в том, что я хочу его проанализировать.

3 Solutions collect form web for “Отображение вывода подпроцесса в stdout и перенаправление его”

Чтобы сохранить подпроцесс 'stdout в переменную для дальнейшей обработки и отобразить ее, пока дочерний процесс запущен по мере ее поступления :

 #!/usr/bin/env python3 from io import StringIO from subprocess import Popen, PIPE with Popen('/path/to/script', stdout=PIPE, bufsize=1, universal_newlines=True) as p, StringIO() as buf: for line in p.stdout: print(line, end='') buf.write(line) output = buf.getvalue() rc = p.returncode 

Чтобы сохранить как stdout subprocess, так и stderr более сложно, потому что вы должны одновременно использовать оба потока, чтобы избежать взаимоблокировки :

 stdout_buf, stderr_buf = StringIO(), StringIO() rc = teed_call('/path/to/script', stdout=stdout_buf, stderr=stderr_buf, universal_newlines=True) output = stdout_buf.getvalue() ... 

где здесь определяется teed_call() .


Обновление: вот более asyncio версия asyncio .


Старая версия:

Вот однопоточное решение, основанное на примере child_process.py из tulip :

 import asyncio import sys from asyncio.subprocess import PIPE @asyncio.coroutine def read_and_display(*cmd): """Read cmd's stdout, stderr while displaying them as they arrive.""" # start process process = yield from asyncio.create_subprocess_exec(*cmd, stdout=PIPE, stderr=PIPE) # read child's stdout/stderr concurrently stdout, stderr = [], [] # stderr, stdout buffers tasks = { asyncio.Task(process.stdout.readline()): ( stdout, process.stdout, sys.stdout.buffer), asyncio.Task(process.stderr.readline()): ( stderr, process.stderr, sys.stderr.buffer)} while tasks: done, pending = yield from asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) assert done for future in done: buf, stream, display = tasks.pop(future) line = future.result() if line: # not EOF buf.append(line) # save for later display.write(line) # display in terminal # schedule to read the next line tasks[asyncio.Task(stream.readline())] = buf, stream, display # wait for the process to exit rc = yield from process.wait() return rc, b''.join(stdout), b''.join(stderr) 

Скрипт запускает команду '/path/to/script и одновременно строит строки как stdout, так и stderr. Строки печатаются на родительский stdout / stderr соответственно и сохраняются как байты для будущей обработки. Чтобы запустить read_and_display() , нам нужен цикл событий:

 import os if os.name == 'nt': loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows asyncio.set_event_loop(loop) else: loop = asyncio.get_event_loop() try: rc, *output = loop.run_until_complete(read_and_display("/path/to/script")) if rc: sys.exit("child failed with '{}' exit code".format(rc)) finally: loop.close() 

p.communicate() ожидает завершения подпроцесса, а затем сразу возвращает весь его результат.

Вы пробовали что-то подобное вместо этого, где вы читаете вывод подпроцесса по очереди?

 p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE) for line in p.stdout: # do something with this individual line print line 

В документе Popen.communicate четко указано:

 Note: The data read is buffered in memory, so do not use this method if the data size is large or unlimited. 

https://docs.python.org/2/library/subprocess.html#subprocess.Popen.communicate

Поэтому, если вам нужен выход в реальном времени, вам нужно использовать что-то вроде этого:

 stream_p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE) while stream_line in stream_p: #Parse it the way you want print stream_line 
  • Необходимо избегать взаимоблокировки подпроцесса без связи
  • Как проверить, есть ли у stdin некоторые данные?
  • Подпроцесс Python - перенаправление stdout / err на два места
  • Как вы передаете данные в STDIN программы из разных локальных / удаленных процессов в Python?
  • Перенаправление stdio из команды в os.system () в Python
  • p.stdout.read () не работает в моих кодах Python 3
  • Многопроцессорность Python: как я могу НАДЕЖДАТЬ перенаправление stdout из дочернего процесса?
  • Могу ли я перенаправить stdout в python в какой-то строковый буфер?
  • Python - лучший язык программирования в мире.