Подтвердить что ты не робот

Печать 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.

Приложение: Это работает для передачи, но я вижу вывод только в конце, и я хотел бы видеть детали передачи, когда это происходит.

4b9b3361

Ответ 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()