Read streaming input from subprocess.communicate()
Чтение потоковых входных данных из subprocess.communicate()
Я использую Python subprocess.communicate() для чтения стандартного вывода из процесса, который выполняется около минуты.
Как я могу распечатать каждую строку этого процесса stdout потоковым способом, чтобы я мог видеть выходные данные по мере их создания, но по-прежнему блокировать завершение процесса, прежде чем продолжить?
subprocess.communicate() кажется, что выдает весь вывод сразу.
Переведено автоматически
Ответ 1
Чтобы получать выходные данные подпроцесса построчно, как только подпроцесс очищает свой буфер стандартного вывода:
#!/usr/bin/env python2 from subprocess import Popen, PIPE
p = Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1) with p.stdout: for line initer(p.stdout.readline, b''): print line, p.wait() # wait for the subprocess to exit
Если стандартный вывод подпроцесса использует буферизацию блоков вместо буферизации строк в неинтерактивном режиме (что приводит к задержке вывода до тех пор, пока дочерний буфер не заполнится или не будет явно сброшен дочерним буфером), тогда вы могли бы попытаться принудительно выполнить небуферизованный вывод, используя pexpect, pty модули или unbuffer, stdbuf, script утилиты, см. Вопрос: Почему бы просто не использовать канал (popen())?
Вот код Python 3:
#!/usr/bin/env python3 from subprocess import Popen, PIPE
with Popen(["cmd", "arg1"], stdout=PIPE, bufsize=1, universal_newlines=True) as p: for line in p.stdout: print(line, end='')
Примечание: В отличие от Python 2, который выводит байтовые строки подпроцесса как есть; Python 3 использует текстовый режим (вывод cmd декодируется с использованием locale.getpreferredencoding(False) кодировки).
Если ls завершается слишком быстро, цикл while может завершиться до того, как вы прочитаете все данные.
Вы можете перехватить остаток в стандартном выводе таким образом:
output = proc.communicate()[0] print output,
Ответ 3
Я считаю, что самый простой способ собирать выходные данные из процесса потоковым способом выглядит следующим образом:
import sys from subprocess import * proc = Popen('ls', shell=True, stdout=PIPE) whileTrue: data = proc.stdout.readline() # Alternatively proc.stdout.read(1024) iflen(data) == 0: break sys.stdout.write(data) # sys.stdout.buffer.write(data) on Python 3.x
Функция readline() or read() должна возвращать пустую строку только в EOF после завершения процесса - в противном случае она заблокируется, если нечего читать (readline() включает перевод строки, поэтому в пустых строках она возвращает "\n"). Это позволяет избежать необходимости в неудобном финальном communicate() вызове после цикла.
Для файлов с очень длинными строками read() может быть предпочтительнее уменьшить максимальное использование памяти - передаваемое ему число произвольно, но его исключение приводит к считыванию всего вывода канала сразу, что, вероятно, нежелательно.
Ответ 4
Если вам нужен неблокирующий подход, не используйте process.communicate(). Если вы установите для subprocess.Popen() аргумента stdout значение PIPE, вы можете прочитать из process.stdout и проверить, выполняется ли процесс по-прежнему с помощью process.poll().