Мой скрипт на Python использует подпроцесс для вызова утилиты Linux, которая работает с большим шумом. Я хочу сохранить все выходные данные в файл журнала и показать часть из них пользователю. Я думал, что сработает следующее, но выходные данные не отображаются в моем приложении, пока утилита не выдаст значительный объем выходных данных.
# fake_utility.py, just generates lots of output over time import time i = 0 whileTrue: print(hex(i)*512) i += 1 time.sleep(0.5)
В родительском процессе:
import subprocess
proc = subprocess.Popen(['python', 'fake_utility.py'], stdout=subprocess.PIPE) for line in proc.stdout: # the real code does filtering here print("test:", line.rstrip())
Поведение, которого я действительно хочу, чтобы скрипт фильтра печатал каждую строку по мере ее получения от подпроцесса, как это делает tee, но в коде Python.
Чего я не понимаю? Возможно ли это вообще?
Переведено автоматически
Ответ 1
Я думаю, проблема в операторе for line in proc.stdout, который считывает весь ввод перед повторением. Решение заключается в использовании readline() вместо:
#filters output import subprocess proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE) whileTrue: line = proc.stdout.readline() ifnot line: break #the real code does filtering here print"test:", line.rstrip()
Конечно, вам все равно придется иметь дело с буферизацией подпроцесса.
Примечание: согласно документации решение с итератором должно быть эквивалентно использованию readline(), за исключением буфера опережающего чтения, но (или именно из-за этого) предлагаемое изменение привело к другим результатам для меня (Python 2.5 в Windows XP).
Ответ 2
Немного опоздал на вечеринку, но был удивлен, не увидев здесь, на мой взгляд, самого простого решения:
import io import subprocess
proc = subprocess.Popen(["prog", "arg"], stdout=subprocess.PIPE) for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): # or another encoding # do something with line
(Для этого требуется Python 3.)
Ответ 3
Действительно, если вы разобрались с итератором, то буферизация теперь может быть вашей проблемой. Вы могли бы сказать python в подпроцессе, чтобы он не буферизовал свои выходные данные.