Мой скрипт на python использует подпроцесс для вызова очень шумной утилиты linux. Я хочу сохранить весь вывод в файл журнала и показать некоторые из них пользователю. Я думал, что следующее будет работать, но вывод не будет отображаться в моем приложении, пока утилита не выдаст значительный объем вывода.
#fake_utility.py, just generates lots of output over time
import time
i = 0
while True:
print hex(i)*512
i += 1
time.sleep(0.5)
#filters output
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.
Чего мне не хватает? Это вообще возможно?
Обновить:
Если a sys.stdout.flush()
добавлено в fake_utility.py, код имеет желаемое поведение в Python 3.1. Я использую Python 2.6. Вы можете подумать, что использование proc.stdout.xreadlines()
будет работать так же, как py3k, но это не так.
Обновление 2:
Вот минимальный рабочий код.
#fake_utility.py, just generates lots of output over time
import sys, time
for i in range(10):
print i
sys.stdout.flush()
time.sleep(0.5)
#display out put line by line
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
#works in python 3.0+
#for line in proc.stdout:
for line in iter(proc.stdout.readline,''):
print line.rstrip()
источник
print line,
вместоprint line.rstrip()
(примечание: запятая в конце).subprocess.communicate()
Ответы:
Прошло много времени с тех пор, как я в последний раз работал с Python, но я думаю, что проблема в утверждении
for line in proc.stdout
, которое читает весь ввод перед его повторением. Решение состоит в том, чтобы использоватьreadline()
вместо:Конечно, вам все равно придется иметь дело с буферизацией подпроцесса.
Примечание: согласно документации решение с итератором должно быть эквивалентно использованию
readline()
, за исключением буфера упреждающего чтения, но (или именно из-за этого) предлагаемое изменение действительно дало для меня другие результаты (Python 2.5 в Windows XP).источник
file.readline()
vs.for line in file
см bugs.python.org/issue3907 (короче: он работает на Python3, использованиеio.open()
на Python 2.6+)for line in iter(proc.stdout.readline, ''):
.for line in proc.stdout
на Python 3 (нет ошибки опережающего чтения) 2.'' != b''
на Python 3 - не копируйте и не вставляйте код вслепую - подумайте, что он делает и как он работает.iter(f.readline, b'')
решение довольно очевидно (а также работает на Python 2, если кому-то интересно). Смысл моего комментария состоял не в том, чтобы обвинить ваше решение (извините, если оно появилось таким образом, я тоже сейчас это прочитал!), А в том, чтобы описать степень симптомов, которые в этом случае весьма серьезны (большинство из Py2 / 3 проблемы приводят к исключениям, в то время как здесь хорошо ведущий себя цикл изменился на бесконечный, и сборка мусора борется с потоком вновь созданных объектов, приводя к колебаниям использования памяти с большим периодом и большой амплитудой).Немного опоздал на вечеринку, но был удивлен, не увидев, что я думаю, самое простое решение здесь:
(Для этого требуется Python 3.)
источник
AttributeError: 'file' object has no attribute 'readable'
py2.7TextIOWrapper
или нет. Вы можете просто обработать исключение.Действительно, если вы разобрались с итератором, буферизация теперь может стать вашей проблемой. Вы можете указать питону в подпроцессе не буферизировать его вывод.
становится
Мне это нужно при вызове Python изнутри Python.
источник
Вы хотите передать эти дополнительные параметры
subprocess.Popen
:Затем вы можете повторить, как в вашем примере. (Протестировано с Python 3.5)
источник
Функция, позволяющая выполнять итерации одновременно
stdout
иstderr
в режиме реального времени построчноЕсли вам нужно получить выходной поток для обоих
stdout
иstderr
одновременно, вы можете использовать следующую функцию.Функция использует очереди для объединения обоих каналов Popen в один итератор.
Здесь мы создаем функцию
read_popen_pipes()
:read_popen_pipes()
в использовании:источник
Вы также можете читать строки без цикла. Работает в python3.6.
источник
list_of_strings = [x.decode('utf-8').rstrip('\n') for x in iter(process.stdout.readlines())]
Я попробовал это с python3, и это сработало, источник
источник
Следующая модификация ответа Ромуло работает для меня на Python 2 и 3 (2.7.12 и 3.6.1):
источник
Не знаю, когда это было добавлено в модуль подпроцесса, но с Python 3 у вас должно получиться использовать
proc.stdout.splitlines()
:источник