Печать stdout в реальном времени из подпроцесса, который требует stdin
Это продолжение этого вопроса, но если я хочу передать аргумент stdin
to subprocess
, как я могу получить вывод в в реальном времени? Это то, что я сейчас имею; Я также попытался заменить Popen
на call
из модуля subprocess
, и это просто приводит к зависанию script.
from subprocess import Popen, PIPE, STDOUT
cmd = 'rsync --rsh=ssh -rv --files-from=- thisdir/ servername:folder/'
p = Popen(cmd.split(), stdout=PIPE, stdin=PIPE, stderr=STDOUT)
subfolders = '\n'.join(['subfolder1','subfolder2'])
output = p.communicate(input=subfolders)[0]
print output
В первом вопросе, где мне не нужно было проходить stdin
, мне предложили использовать p.stdout.readline
, там нет места, где можно было бы что-либо передать stdin
.
Приложение: Это работает для передачи, но я вижу вывод только в конце, и я хотел бы видеть детали передачи, когда это происходит.
Ответы
Ответ 1
Чтобы захватить stdout из подпроцесса в реальном времени, вам нужно точно определить, какое поведение вы хотите; в частности, вам нужно решить, хотите ли вы иметь дело с выводами за строкой или символьным символом, и хотите ли вы блокировать пока ожидаете вывода или сможете что-то сделать во время ожидания.
Похоже, вам, вероятно, будет достаточно, чтобы ваш случай читал выходные данные в буферизованном порядке, блокируя до тех пор, пока не появится каждая полная строка, что означает, что удобные функции, предоставляемые subprocess
, достаточно хороши:
p = subprocess.Popen(some_cmd, stdout=subprocess.PIPE)
# Grab stdout line by line as it becomes available. This will loop until
# p terminates.
while p.poll() is None:
l = p.stdout.readline() # This blocks until it receives a newline.
print l
# When the subprocess terminates there might be unconsumed output
# that still needs to be processed.
print p.stdout.read()
Если вам нужно записать в stdin процесса, просто используйте другой канал:
p = subprocess.Popen(some_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
# Send input to p.
p.stdin.write("some input\n")
p.stdin.flush()
# Now start grabbing output.
while p.poll() is None:
l = p.stdout.readline()
print l
print p.stdout.read()
Повторите другой ответ, нет необходимости косвенным путем через файл, чтобы передать вход в подпроцесс.
Ответ 2
что-то вроде этого я думаю
from subprocess import Popen, PIPE, STDOUT
p = Popen('c:/python26/python printingTest.py', stdout = PIPE,
stderr = PIPE)
for line in iter(p.stdout.readline, ''):
print line
p.stdout.close()
используя итератор, будет возвращать результаты в реальном времени.
для отправки ввода в stdin вам понадобится что-то вроде
other_input = "some extra input stuff"
with open("to_input.txt","w") as f:
f.write(other_input)
p = Popen('c:/python26/python printingTest.py < some_input_redirection_thing',
stdin = open("to_input.txt"),
stdout = PIPE,
stderr = PIPE)
это будет похоже на команду linux shell
%prompt%> some_file.o < cat to_input.txt
см. alps ответ для лучшего перехода к stdin
Ответ 3
Если вы передадите весь свой вход перед началом чтения вывода, а если "в реальном времени" вы имеете в виду всякий раз, когда подпроцесс сбрасывает свой буфер stdout:
from subprocess import Popen, PIPE, STDOUT
cmd = 'rsync --rsh=ssh -rv --files-from=- thisdir/ servername:folder/'
p = Popen(cmd.split(), stdout=PIPE, stdin=PIPE, stderr=STDOUT, bufsize=1)
subfolders = '\n'.join(['subfolder1','subfolder2'])
p.stdin.write(subfolders)
p.stdin.close() # eof
for line in iter(p.stdout.readline, ''):
print line, # do something with the output here
p.stdout.close()
rc = p.wait()