Чтение в реальном времени из subprocess.stdout в Windows
Подчеркнем, что проблема заключается в чтении в реальном времени, а не в чтении без блокировки. Это было задано ранее, например, subprocess.Popen.stdout - чтение stdout в режиме реального времени (снова). Но удовлетворительного решения не было предложено.
В качестве примера, следующий код пытается симулировать оболочку python.
import subprocess
p = subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
line = input('>>> ')
p.stdin.write(line.encode())
print('>>> ', p.stdout.read().decode())
Тем не менее, он будет заблокирован при чтении из p.stdout
, Обыскав вокруг, я нашел следующие два возможных решения.
В то время как 1-й вариант может работать и работать только на Linux, 2-й вариант просто превращает блокирующее чтение в неблокирующее чтение, т.е. я не могу получить вывод подпроцесса в реальном времени. Например, если я введу ' print("hello")
"Я ничего не получу от p.stdout
используя 2-й раствор.
Возможно, кто-то посоветует p.communite
, К сожалению, это не подходит в этом случае, так как это закроет стандартный ввод, как описано здесь.
Итак, есть ли решения для Windows?
Отредактировано: даже если -u
включен и p.stdout.read
заменяется на p.stdout.readline
проблема все еще существует.
import subprocess
p = subprocess.Popen(['python', '-u'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
line = input('>>> ')
p.stdin.write(line.encode())
p.stdin.flush()
print('>>> ', p.stdout.readline().decode())
Решение: Ниже приведен окончательный код, основанный на ответе и комментариях Дж. Ф. Себастьяна.
from subprocess import Popen, PIPE, STDOUT
with Popen(
['python', '-i', '-q'],
stdin=PIPE, stdout=PIPE, stderr=STDOUT,
bufsize=0
) as process:
while True:
line = input('>>> ')
if not line:
break
process.stdin.write((line+'\n').encode())
print(process.stdout.readline().decode(), end='')
Следует отметить, что программа зависает, когда команда не запускает вывод.
1 ответ
Вот полный рабочий пример, который использует подпроцесс в интерактивном режиме:
#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, DEVNULL
with Popen([sys.executable, '-i'], stdin=PIPE, stdout=PIPE, stderr=DEVNULL,
universal_newlines=True) as process:
for i in range(10):
print("{}**2".format(i), file=process.stdin, flush=True)
square = process.stdout.readline()
print(square, end='')
Вот еще один пример: как запустить [sys.executable, '-u', 'test.py']
в интерактивном режиме.