Python 将子进程输出显示到标准输出并将其重定向
我正在通过Python的子流程模块运行一个脚本。目前我使用:Python 将子进程输出显示到标准输出并将其重定向,python,subprocess,stdout,Python,Subprocess,Stdout,我正在通过Python的子流程模块运行一个脚本。目前我使用: p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = p.communicate() 然后将结果打印到标准输出。这一切都很好,但由于脚本需要很长时间才能完成,因此我还需要从脚本到stdout的实时输出。我之所以对输出进行管道化处理,是因为我想对其进行解析。然后立即返回其整个输出 您是否尝试过这样
p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result = p.communicate()
然后将结果打印到标准输出。这一切都很好,但由于脚本需要很长时间才能完成,因此我还需要从脚本到stdout的实时输出。我之所以对输出进行管道化处理,是因为我想对其进行解析。然后立即返回其整个输出
您是否尝试过这样的方法,逐行读取子流程输出
p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
for line in p.stdout:
# do something with this individual line
print line
Popen.communicate文件明确指出:
Note: The data read is buffered in memory, so do not use this method if the data size is large or unlimited.
因此,如果您需要实时输出,则需要使用以下内容:
stream_p = subprocess.Popen('/path/to/script', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while stream_line in stream_p:
#Parse it the way you want
print stream_line
要将子流程的stdout保存到变量以供进一步处理,请执行以下操作: 保存子流程的stdout和stderr更加复杂,因为您应该: 在哪里
更新:这里是
旧版本: 以下是基于以下内容的单线程解决方案: 脚本运行
'/path/to/script
命令并同时逐行读取其stdout和stderr。这些行会相应地打印到父级的stdout/stderr,并保存为bytestrings以备将来处理。要运行read\u and\u display()
corroutine,我们需要一个事件循环:
import os
if os.name == 'nt':
loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
try:
rc, *output = loop.run_until_complete(read_and_display("/path/to/script"))
if rc:
sys.exit("child failed with '{}' exit code".format(rc))
finally:
loop.close()
这会将stdout和stderr打印到终端,并将stdout和stderr保存到变量中:
从子流程导入Popen、PIPE、STDOUT
将Popen(args,stdout=PIPE,stderr=stdout,text=True,bufsize=1)作为p:
output=“”.join([print(buf,end=“”)或p.stdout中buf的buf])
但是,根据您具体执行的操作,这一点可能需要注意:通过使用stderr=STDOUT
,我们无法再区分STDOUT和stderr,通过调用print
,您的输出将始终打印到STDOUT,不管它是来自STDOUT还是stderr
对于Python<3.7,您需要使用universal\u新行
而不是text
版本3.7中新增:文本作为更可读的别名添加到universal_新行中
来源:related:related:如果不需要访问Popen的所有较低级别选项,可以尝试使用subprocess.call(['/path/to/script'])。默认情况下,输出应该流到标准输出。@lukelh:
call('/path/to/script')
将显示输出,但您不能同时捕获它(稍后在OP请求时对其进行解析)。相关:如果子进程生成足够的输出来填充OS标准输出管道缓冲区(在我的机器上为65K),则它将挂起。您也应该同时使用p.stderr
。由于预读错误,p.stdout中的行的将以突发方式打印。您可以对iter中的行使用(p.stdout.readline,b'')
<代码>打印行
将打印双换行。您可以使用打印行(注意:逗号)来避免它。使用stderr
也很重要。我假设在冗长的数据流中缓冲行不会是一个问题,但这也是一个需要考虑的问题。“脚本需要很长时间才能完成”——这意味着,如果脚本将进程写入STDRR,那么它就可以停顿。
stdout_buf, stderr_buf = StringIO(), StringIO()
rc = teed_call('/path/to/script', stdout=stdout_buf, stderr=stderr_buf,
universal_newlines=True)
output = stdout_buf.getvalue()
...
import asyncio
import sys
from asyncio.subprocess import PIPE
@asyncio.coroutine
def read_and_display(*cmd):
"""Read cmd's stdout, stderr while displaying them as they arrive."""
# start process
process = yield from asyncio.create_subprocess_exec(*cmd,
stdout=PIPE, stderr=PIPE)
# read child's stdout/stderr concurrently
stdout, stderr = [], [] # stderr, stdout buffers
tasks = {
asyncio.Task(process.stdout.readline()): (
stdout, process.stdout, sys.stdout.buffer),
asyncio.Task(process.stderr.readline()): (
stderr, process.stderr, sys.stderr.buffer)}
while tasks:
done, pending = yield from asyncio.wait(tasks,
return_when=asyncio.FIRST_COMPLETED)
assert done
for future in done:
buf, stream, display = tasks.pop(future)
line = future.result()
if line: # not EOF
buf.append(line) # save for later
display.write(line) # display in terminal
# schedule to read the next line
tasks[asyncio.Task(stream.readline())] = buf, stream, display
# wait for the process to exit
rc = yield from process.wait()
return rc, b''.join(stdout), b''.join(stderr)
import os
if os.name == 'nt':
loop = asyncio.ProactorEventLoop() # for subprocess' pipes on Windows
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
try:
rc, *output = loop.run_until_complete(read_and_display("/path/to/script"))
if rc:
sys.exit("child failed with '{}' exit code".format(rc))
finally:
loop.close()