Вопрос-Ответ

Constantly print Subprocess output while process is running

Постоянная печать выходных данных подпроцесса во время выполнения процесса

Для запуска программ из моих Python-скриптов я использую следующий метод:

def execute(command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = process.communicate()[0]
exitCode = process.returncode

if (exitCode == 0):
return output
else:
raise ProcessException(command, exitCode, output)

Поэтому, когда я запускаю процесс, подобный Process.execute("mvn clean install"), моя программа ожидает завершения процесса, и только тогда я получаю полный вывод моей программы. Это раздражает, если я запускаю процесс, для завершения которого требуется некоторое время.

Могу ли я позволить моей программе записывать выходные данные процесса построчно, опрашивая выходные данные процесса перед его завершением в цикле или что-то в этом роде?

Я нашел эту статью, которая может быть связана.

Переведено автоматически
Ответ 1

Вы можете использовать iter для обработки строк, как только команда их выводит: lines = iter(fd.readline, ""). Вот полный пример, показывающий типичный вариант использования (спасибо @jfs за помощь):

from __future__ import print_function # Only Python 2.x
import subprocess

def execute(cmd):
popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True)
for stdout_line in iter(popen.stdout.readline, ""):
yield stdout_line
popen.stdout.close()
return_code = popen.wait()
if return_code:
raise subprocess.CalledProcessError(return_code, cmd)

# Example
for path in execute(["locate", "a"]):
print(path, end="")
Ответ 2

Печатать выходные данные подпроцесса построчно, как только его буфер стандартного вывода очищается в Python 3:

from subprocess import Popen, PIPE, CalledProcessError

with Popen(cmd, stdout=PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
print(line, end='') # process line here

if p.returncode != 0:
raise CalledProcessError(p.returncode, p.args)

Обратите внимание: вам не нужно p.poll() -- цикл завершается при достижении eof. И вам не нужно iter(p.stdout.readline, '') -- ошибка с опережением чтения исправлена в Python 3.

Смотрите также, Python: считывание потоковых входных данных из subprocess.communicate().

Ответ 3

Хорошо, мне удалось решить это без потоков (приветствуются любые предложения, почему использование потоков было бы лучше), используя фрагмент из этого вопроса, перехватывающий стандартный вывод подпроцесса во время его выполнения

def execute(command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

# Poll process for new output until finished
while True:
nextline = process.stdout.readline()
if nextline == '' and process.poll() is not None:
break
sys.stdout.write(nextline)
sys.stdout.flush()

output = process.communicate()[0]
exitCode = process.returncode

if (exitCode == 0):
return output
else:
raise ProcessException(command, exitCode, output)
Ответ 4

На самом деле есть действительно простой способ сделать это, когда вы просто хотите print получить выходные данные:

import subprocess
import sys

def execute(command):
subprocess.check_call(command, shell=True, stdout=sys.stdout, stderr=subprocess.STDOUT)

Здесь мы просто указываем подпроцессу на наш собственный stdout и используем существующий api success или exception.

python subprocess