Вопрос по python, perl, process – Перехват stdout в реальном времени из другого процесса в Python

3

Я хотел бы запустить системный процесс, перехватить вывод и изменить его в режиме реального времени, построчно, в скрипте Python.

Моя лучшая попытка, которая ожидает завершения процесса перед печатью:

#!/usr/bin/env python
import subprocess

cmd = "waitsome.py"
proc = subprocess.Popen(cmd, shell=True, bufsize=256, stdout=subprocess.PIPE)
for line in proc.stdout:
    print ">>> " + line.rstrip()

Сценарийwaitsome.py просто печатает строку каждые полсекунды:

#!/usr/bin/env python
import time
from sys import stdout

print "Starting"
for i in range(0,20):
    time.sleep(0.5)
    print "Hello, iteration", i
    stdout.flush()

Есть ли простое решение, чтобы получитьsubprocess разрешить перебор выходных данных в режиме реального времени? Должен ли я использовать темы?

Когда-то я писал на Perl, и это было очень просто:

open(CMD, "waitsome.py |");
while (<CMD>) {
    print ">>> $_";
}
close(CMD);
Извините, я только увидел первый и понял, что это проблема сsubprocess' буферизация, а не родительского сценария Python. Seth Johnson

Ваш Ответ

2   ответа
13

Зацикливание на файле неизбежно буферизует вещи большими порциями - известная проблема во всех реализациях Python 2. *. Это работает так, как вы намереваетесь в Python 3.1, с последним циклом, который немного отличается:

for line in proc.stdout:
    print(">>> " + str(line.rstrip()))

Если обновление до Python 3.1 нецелесообразно (и я знаю, что это будет часто!), Идите другим путем и напишите цикл старомодным способом - следующая версия цикла работает так, как вы собираетесь в Python 2. * :

while True:
    line = proc.stdout.readline()
    if not line:
        break
    print ">>> " + line.rstrip()
Это также работает в Python 3.0
for line in iter(proc.stdout.readline, ''): print ">>>", line, может использоваться вместо цикла while в Python 2.
Да, но теперь, когда вышел Python 3.1 (с намного лучшей реализацией всего стека ввода / вывода), нет никаких причин придерживаться версии 3.0 (это была определенно переходная версия ;-).
0

Все это может быть заключено в итератор как:

def subprocess_readlines(out):
    while True:
        line = out.readline()
        if not line:
            return
        yield line

И называется как:

for line in proc.stdout:
    print ">>>", line.rstrip()
Буферизация в Python сильно изменилась с тех пор, как я написал оригинальный вопрос :) Да, то, что потребовало много усилий для Python 2.5, теперь можно выполнить в несколько строк. Seth Johnson

Похожие вопросы