Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将子进程输出显示到标准输出并将其重定向_Python_Subprocess_Stdout - Fatal编程技术网

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的实时输出。我之所以对输出进行管道化处理,是因为我想对其进行解析。然后立即返回其整个输出 您是否尝试过这样

我正在通过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)
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()