Перехват stdout подпроцесса во время его работы - PullRequest
22 голосов
/ 09 февраля 2009

Если это мой подпроцесс:

import time, sys
for i in range(200):
    sys.stdout.write( 'reading %i\n'%i )
    time.sleep(.02)

И это скрипт, управляющий и изменяющий вывод подпроцесса:

import subprocess, time, sys

print 'starting'

proc = subprocess.Popen(
    'c:/test_apps/testcr.py',
    shell=True,
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE  )

print 'process created'

while True:
    #next_line = proc.communicate()[0]
    next_line = proc.stdout.readline()
    if next_line == '' and proc.poll() != None:
        break
    sys.stdout.write(next_line)
    sys.stdout.flush()

print 'done'

Почему readline и communicate ожидают завершения процесса? Есть ли простой способ передать (и изменить) стандартный вывод подпроцесса в реальном времени?

Кстати, я видел это , но мне не нужны функции ведения журнала (и я не потрудился понять его)

Я на Windows XP.

Ответы [ 2 ]

15 голосов
/ 09 февраля 2009

Как уже упоминал Чарльз, проблема в буферизации. Я столкнулся с подобной проблемой при написании некоторых модулей для SNMPd и решил ее, заменив стандартный вывод на версию с автоматической очисткой.

Я использовал следующий код, вдохновленный некоторыми постами на ActiveState:

class FlushFile(object):
    """Write-only flushing wrapper for file-type objects."""
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

# Replace stdout with an automatically flushing version
sys.stdout = FlushFile(sys.__stdout__)
8 голосов
/ 09 февраля 2009

Вывод процесса буферизирован. В других операционных системах UNIXy (или Cygwin) доступен модуль pexpect , который перечисляет все необходимые заклинания, чтобы избежать проблем, связанных с буферизацией. Однако для этих заклинаний требуется работающий pty модуль , который недоступен в собственных (не cygwin) сборках Win32 Python.

В примере, где вы управляете подпроцессом, вы можете просто вызвать его sys.stdout.flush(), где это необходимо, но для произвольных подпроцессов эта опция недоступна.

См. Также вопрос "Почему бы просто не использовать канал (popen ())?" в FAQ по pexpect.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...