В настоящее время все остальные ответы не обрабатывают буферизацию на стороне дочернего подпроцесса, если подпроцесс не является скриптом Python, который принимает флаг -u
. Смотрите "Q: Почему бы просто не использовать канал (popen ())?" в документации pexpect .
Чтобы смоделировать флаг -u
для некоторых программ на основе C stdio (FILE*
), вы можете попробовать stdbuf
.
Если вы проигнорируете это, то ваш вывод не будет правильно чередоваться и может выглядеть следующим образом:
stderr
stderr
...large block of stdout including parts that are printed before stderr...
Вы можете попробовать это с помощью следующей клиентской программы, заметьте разницу с / без флага -u
(['stdbuf', '-o', 'L', 'child_program']
также исправляет вывод):
#!/usr/bin/env python
from __future__ import print_function
import random
import sys
import time
from datetime import datetime
def tprint(msg, file=sys.stdout):
time.sleep(.1*random.random())
print("%s %s" % (datetime.utcnow().strftime('%S.%f'), msg), file=file)
tprint("stdout1 before stderr")
tprint("stdout2 before stderr")
for x in range(5):
tprint('stderr%d' % x, file=sys.stderr)
tprint("stdout3 after stderr")
В Linux вы можете использовать pty
, чтобы получить то же поведение, что и при интерактивном выполнении подпроцесса, например, вот модифицированный ответ @T.Rojan :
import logging, os, select, subprocess, sys, pty
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
master_fd, slave_fd = pty.openpty()
p = subprocess.Popen(args,stdout=slave_fd, stderr=subprocess.PIPE, close_fds=True)
with os.fdopen(master_fd) as stdout:
poll = select.poll()
poll.register(stdout, select.POLLIN)
poll.register(p.stderr,select.POLLIN | select.POLLHUP)
def cleanup(_done=[]):
if _done: return
_done.append(1)
poll.unregister(p.stderr)
p.stderr.close()
poll.unregister(stdout)
assert p.poll() is not None
read_write = {stdout.fileno(): (stdout.readline, logger.info),
p.stderr.fileno(): (p.stderr.readline, logger.error)}
while True:
events = poll.poll(40) # poll with a small timeout to avoid both
# blocking forever and a busy loop
if not events and p.poll() is not None:
# no IO events and the subprocess exited
cleanup()
break
for fd, event in events:
if event & select.POLLIN: # there is something to read
read, write = read_write[fd]
line = read()
if line:
write(line.rstrip())
elif event & select.POLLHUP: # free resources if stderr hung up
cleanup()
else: # something unexpected happened
assert 0
sys.exit(p.wait()) # return child's exit code
Предполагается, что stderr всегда небуферизован / буферизован, а stdout буферизован в интерактивном режиме. Только полные строки читаются. Программа может блокироваться, если в выводе есть незавершенные строки.