Я пытаюсь написать сценарий оболочки для программы командной строки (svnadmin verify), которая будет отображать хороший индикатор выполнения операции. Это требует, чтобы я мог видеть каждую строку вывода завернутой программы, как только она выводится.
Я решил, что просто выполню программу, используя subprocess.Popen
, использую stdout=PIPE
, затем прочитаю каждую строку по мере ее поступления и буду действовать соответствующим образом. Однако, когда я запустил следующий код, результат казался где-то в буфере, в результате чего он отображался в двух частях: строки с 1 по 332, затем с 333 по 439 (последняя строка вывода).
from subprocess import Popen, PIPE, STDOUT
p = Popen('svnadmin verify /var/svn/repos/config', stdout = PIPE,
stderr = STDOUT, shell = True)
for line in p.stdout:
print line.replace('\n', '')
Немного посмотрев документацию по подпроцессу, я обнаружил bufsize
параметр to Popen
, поэтому я попытался установить bufsize на 1 (буферизовать каждую строку) и 0 (без буфера), но ни одно значение, похоже, не изменило способ доставки строк.
В этот момент я начал цепляться за соломинку, поэтому написал следующий цикл вывода:
while True:
try:
print p.stdout.next().replace('\n', '')
except StopIteration:
break
но получил тот же результат.
Можно ли получить вывод программы в реальном времени программы, выполняемой с помощью подпроцесса? Есть ли в Python какой-либо другой вариант, который (не exec*
) совместим с продвижением вперед ?
источник
sydout=PIPE
чтобы подпроцесс записывал прямо на вашу консоль, минуя родительский процесс?Ответы:
Я пробовал это, и почему-то пока код
буферизуется агрессивно, вариант
не. По-видимому, это известная ошибка: http://bugs.python.org/issue3907 (29 августа 2018 г. проблема закрыта)
источник
while p.poll() is None
вместоwhile True
и удалитьif not line
print(line.decode('utf-8').rstrip())
.PYTHONUNBUFFERED=1
. Это особенно полезно для бесконечных выходовисточник
p.stdout.close()
непонятно.Вы можете напрямую направить вывод подпроцесса в потоки. Упрощенный пример:
источник
.communicate()
? Или содержимое потеряно для родительских потоков stderr / stdout?communicate()
для возвращаемого метода нет методаCompletedProcess
. Такжеcapture_output
является взаимоисключающим сstdout
иstderr
.Вы можете попробовать это:
Если вы используете readline вместо read, в некоторых случаях входное сообщение не будет распечатано. Попробуйте выполнить это с помощью команды, требующей встроенного ввода, и убедитесь в этом сами.
источник
Streaming подпроцесс STDIN и STDOUT с asyncio в Python блоге по Кевин Маккарти показывает , как сделать это с asyncio:
источник
import nest_asyncio; nest_asyncio.apply()
и использовать команду оболочки, т.е.process = await create_subprocess_shell(*command, stdout=PIPE, stderr=PIPE, shell=True)
вместоprocess = await create_subprocess_exec(...)
. Ура!Устранена проблема вывода в реальном времени: я столкнулся с аналогичной проблемой в Python при захвате вывода в реальном времени из программы c. Я добавил " fflush (stdout) ;" в моем коде C. Это сработало для меня. Вот фрагмент кода
<< Программа C >>
<< Программа Python >>
<< ВЫВОД >> Печать: Счетчик 1 Печать: Счет 2 Печать: Счет 3
Надеюсь, поможет.
~ Сайрам
источник
flush(stdout)
) на C ++. Спасибо!Некоторое время назад я столкнулся с той же проблемой. Мое решение заключалось в том, чтобы отказаться от итерации
read
метода, который вернется немедленно, даже если ваш подпроцесс не завершен и т. Д.источник
В зависимости от варианта использования вы также можете отключить буферизацию в самом подпроцессе.
Если подпроцессом будет процесс Python, вы можете сделать это до вызова:
Или, в качестве альтернативы, передайте это в
env
аргументеPopen
.В противном случае, если вы работаете в Linux / Unix, вы можете использовать этот
stdbuf
инструмент. Например:См. Также здесь about
stdbuf
или другие варианты.(См. Также здесь тот же ответ.)
источник
Я использовал это решение для получения вывода в реальном времени в подпроцессе. Этот цикл остановится, как только процесс завершится, исключая необходимость в инструкции break или возможном бесконечном цикле.
источник
if out=='': break
послеout = sub_process...
Найдено эту функцию «подключи и работай» здесь . Работал как шарм!
источник
stderr=subprocess.STDOUT
действительно очень помогает при захвате потоковых данных. Я поддерживаю это.Вы можете использовать итератор для каждого байта на выходе подпроцесса. Это позволяет встроенное обновление (строки, заканчивающиеся на '\ r', перезаписывают предыдущую строку вывода) из подпроцесса:
источник
В Python 3.x процесс может зависнуть, потому что вывод представляет собой массив байтов, а не строку. Убедитесь, что вы декодируете его в строку.
Начиная с Python 3.6 это можно сделать с помощью параметра
encoding
в конструкторе Popen . Полный пример:Обратите внимание , что этот код редиректов
stderr
наstdout
и ручки вывода ошибок .источник
Использование pexpect [ http://www.noah.org/wiki/Pexpect ] с неблокирующими строками чтения решит эту проблему. Это связано с тем, что каналы буферизуются, и поэтому вывод вашего приложения буферизуется каналом, поэтому вы не можете добраться до этого вывода, пока буфер не заполнится или процесс не завершится.
источник
Полное решение:
источник
universal_newlines=True
их дляPopen()
вызова, вам, вероятно, не нужно также вводить собственную обработку их - в этом весь смысл опции.Это базовый скелет, который я всегда использую для этого. Это упрощает реализацию тайм-аутов и позволяет справляться с неизбежными зависаниями.
источник
(Это решение было протестировано с Python 2.7.15)
Вам просто нужно sys.stdout.flush () после чтения / записи каждой строки:
источник
Несколько ответов, предлагающих python 3.x или pthon 2.x, код ниже будет работать для обоих.
источник