如何将stdout重定向到屏幕,同时保存到变量

时间:2016-10-04 22:12:48

标签: python

我正在尝试将stdout重定向到屏幕,同时保存到变量并在AttributeError: __exit__行遇到错误with proc.stdout:,是否有人可以告诉我如何完成此操作?

...............
proc = subprocess.Popen(cmd.split(' '), stderr=subprocess.PIPE)
try:
    proc.wait(timeout=time_out) 
except TimeoutExpired as e:
    print e
    proc.kill()
with proc.stdout:
    for line in proc.stdout:
        print line

错误: -

    with proc.stdout:
AttributeError: __exit__

更新 -

proc = subprocess.Popen(cmd.split(' '),stdout=subprocess.PIPE )
print "Executing %s"%cmd
try:
    proc.wait(timeout=time_out)//HUNG here until timeout kicks-in
except TimeoutExpired as e:
    print e
    proc.kill()
with proc.stdout as stdout:
    for line in stdout:
        print line,

2 个答案:

答案 0 :(得分:0)

创建Popen对象时,设置了stderr。当你打开stdout时,子进程无法打开它,因为你已经设置了stderr。您可以通过将stdout=subprocess.PIPE添加到Popen对象args,或者通过with proc.stderr而不是with proc.stderr来解决此问题。另外,你想稍微改变你的声明,就像这样。

with proc.stdout as stdout:
    for line in stdout:
        sys.stdout.write(line)

答案 1 :(得分:0)

一旦你stdout成为PIPE,你就可以创建一个循环来读取管道并将其写入任意数量的地方。处理stderr会使情况变得有点棘手,因为您还需要背景阅读器。因此,创建一个线程和一个写入多个文件的实用程序,您就完成了。

import sys
import threading
from StringIO import StringIO
import subprocess as subp
import shlex

def _file_copy_many(fp, *write_to):
    """Copy from one file object to one or more file objects"""
    while True:
        buf = fp.read(65536)
        if not buf:
            return
        for fp in write_to:
            fp.write(buf)

# for test
cmd = "ls -l"

# will hold stdout and stderr
outbuf = StringIO()
errbuf = StringIO()

# run the command and close its stdin
proc = subp.Popen(shlex.split(cmd), stdin=subp.PIPE, stdout=subp.PIPE, 
    stderr=subp.PIPE)
proc.stdin.close()

# background thread to write stderr to buffer
stderr_thread = threading.Thread(target=_file_copy_many, 
    args=(proc.stderr, errbuf))
stderr_thread.start()

# write stdout to screen and buffer then wait for program completion
_file_copy_many(proc.stdout, sys.stdout, outbuf)
return_code = proc.wait()

# wait for err thread
stderr_thread.join()

# use buffers
print outbuf.tell(), errbuf.tell()
outbuf.seek(0)
errbuf.seek(0)

这类似于subprocess.Popen.communicate所做但写入更多目的地。