Python 从需要 stdin 的子进程实时打印 stdout

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17411966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 08:08:03  来源:igfitidea点击:

printing stdout in realtime from a subprocess that requires stdin

pythonsubprocess

提问by hatmatrix

This is a follow up to this question, but if I want to pass an argument to stdinto subprocess, how can I get the output in real time? This is what I currently have; I also tried replacing Popenwith callfrom the subprocessmodule and this just leads to the script hanging.

这是对这个问题的跟进,但如果我想将参数传递stdinsubprocess,我怎样才能实时获得输出?这就是我目前拥有的;我也尝试从模块中替换Popen,这只会导致脚本挂起。callsubprocess

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

In the former question where I did not have to pass stdinI was suggested to use p.stdout.readline, there there is no room there to pipe anything to stdin.

在我不必通过的前一个问题中,我stdin被建议使用p.stdout.readline,那里没有空间可以将任何东西通过管道输送到stdin.

Addendum: This works for the transfer, but I see the output only at the end and I would like to see the details of the transfer while it's happening.

附录:这适用于转移,但我只在最后看到输出,我想在转移发生时查看转移的详细信息。

采纳答案by Alp

In order to grab stdout from the subprocess in real time you need to decide exactly what behavior you want; specifically, you need to decide whether you want to deal with the output line-by-line or character-by-character, and whether you want to block while waiting for output or be able to do something else while waiting.

为了实时从子进程中获取标准输出,您需要准确决定您想要什么行为;具体来说,您需要决定是要逐行处理输出还是逐字符处理输出,以及是在等待输出时阻塞还是在等待时能够做其他事情。

It looks like it will probably suffice for your case to read the output in line-buffered fashion, blocking until each complete line comes in, which means the convenience functions provided by subprocessare good enough:

看起来您的情况以行缓冲方式读取输出可能就足够了,阻塞直到每个完整的行进来,这意味着提供的便利功能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()

If you need to write to the stdin of the process, just use another pipe:

如果您需要写入进程的标准输入,只需使用另一个管道:

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()

Pacethe other answer, there's no need to indirect through a file in order to pass input to the subprocess.

吴佩慈对方的回答,没有必要通过间接以文件通过输入到子进程。

回答by Joran Beasley

something like this I think

我认为这样的事情

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()

using an iterator will return live results basically ..

使用迭代器基本上会返回实时结果..

in order to send input to stdin you would need something like

为了将输入发送到标准输入,您需要类似的东西

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)

this would be similar to the linux shell command of

这将类似于 linux shell 命令

%prompt%> some_file.o < cat to_input.txt

see alps answer for better passing to stdin

请参阅 alps 答案以更好地传递到标准输入

回答by jfs

If you pass all your input before starting reading the output and if by "real-time" you mean whenever the subprocess flushes its stdout buffer:

如果在开始读取输出之前传递所有输入,并且“实时”表示子进程刷新其标准输出缓冲区时:

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()