子进程在 PyCharm 中正确显示 sys.stdout 但在控制台中不正确

Subprocess displays sys.stdout correctly in PyCharm but not in the console

我有一个小的 Python 程序,它从名为 commandwrapperpip 包中执行终端命令(它是 subprocess.popen 的包装器:https://pypi.python.org/pypi/commandwrapper/0.7).我也在尝试将实时输出捕获到控制台和文件。

我有代码:

class Tee(object):
    def __init__(self, *files):
        self.files = files
    def write(self, obj):
        for f in self.files:
            f.write(obj)
            f.flush()
    def flush(self) :
        for f in self.files:
            f.flush()

# Set the stdout/stderr to Tee()
out = open(stdout_log, 'w')
stdout_reset = sys.stdout
sys.stdout = Tee(sys.stdout, out)

process = commandwrapper.WrapCommand(command, shell=True) # Also tried False with same behaivor.
cmd = process.prepareToRun()

# Stream the output to the console and stdoutfiles
while cmd.poll() is None:
    msg_out = cmd.stdout.readline()
    sys.stdout.write(msg_out)
    sys.stdout.flush()

out.close()

当我在 PyCharm 中 运行 时,这非常有效。 command 的输出被写入文件并实时显示在终端控制台上。

但是,当我运行终端中的相同代码时,控制台上没有显示输出。怎么会这样? stdout 已正确捕获到文件中,但没有任何内容写入控制台。

任何人都可以看出此代码可以正常工作并按 PyCharm 中的预期运行但不向终端显示任何标准输出的任何原因吗?我在这里不知所措。如果有的话,如果行为被逆转,我可以处理它。

使用 OSX Yosemite 和 运行宁 bash.

您需要更改轮询的逻辑,我使用了 Popen,但如果您愿意,也可以使用包装器:

out = open(stdout_log, 'w')
stdout_reset = sys.stdout
sys.stdout = Tee(sys.stdout, out)
from subprocess import Popen,PIPE,STDOUT
process = Popen([list_of_cmds],stdout=PIPE,stderr=STDOUT)
# Stream the output to the console and stdoutfiles
for line in iter(process.stdout.readline,""):
    sys.stdout.write(line)


out.close()

应用相同的逻辑适用于 commandwrapper 库:

process = commandwrapper.WrapCommand(command, shell=True) # Also tried False with same behaivor.
cmd = process.prepareToRun()
# Stream the output to the console and stdoutfiles
for line in iter(cmd.stdout.readline,""):
    sys.stdout.write(line)

即使子进程已经退出,即 cmd.poll() is not None 也可能在管道中留下缓冲输出。如果在 while cmd.poll() is not None 循环结束后调用 cmd.stdout.read() 就可以看到它。

不重现错误 Tee, commandwrapper:

#!/usr/bin/env python
import sys
import time
from subprocess import Popen, PIPE

#XXX DO NOT USE THE CODE -- ITS PURPOSE IS TO DEMONSTRATE THE ISSUE
p = Popen([sys.executable, '-c', "import os; os.write(1, b'abc')"],
          stdout=PIPE, bufsize=0) # no buffering in the parent
time.sleep(0.3) # allow the child to exit
while p.poll() is None: # poll() should return non-None value
    assert 0, "it is never run unless the computer is slow"
    line = p.stdout.readline()
    print(line)

output = p.stdout.read() #
print("the output left after the child has died: %r" % (output,))
assert len(output) >= 3

查看这些帖子,了解如何实时读取子进程的输出以及如何同时将其重定向到文件和终端:

  • Python: read streaming input from subprocess.communicate()
  • How do I push a subprocess.call() output to terminal and file?
  • Subprocess.Popen: cloning stdout and stderr both to terminal and variables
  • Python subprocess get children's output to file and terminal?