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

Python 子流程在PyCharm中正确显示sys.stdout,但在控制台中不正确显示,python,subprocess,pycharm,stdout,Python,Subprocess,Pycharm,Stdout,我有一个小型Python程序,它从名为commandwrapper的pip包(它是subprocess.popen:)执行终端命令。我还试图捕获控制台和文件的实时输出 我有密码: class Tee(object): def __init__(self, *files): self.files = files def write(self, obj): for f in self.files: f.write(obj)

我有一个小型Python程序,它从名为
commandwrapper
pip
包(它是
subprocess.popen
:)执行终端命令。我还试图捕获控制台和文件的实时输出

我有密码:

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中运行时,这非常有效。
命令的输出将写入文件并实时显示在终端控制台上

但是,当我在终端中运行相同的代码时,控制台上不会显示任何输出。这怎么可能?
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
lib中应用相同的逻辑:

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()不是None
管道中仍可能有缓冲输出。如果在
while cmd.poll()不是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
有关如何实时读取子流程的输出以及如何同时将其重定向到文件和终端,请参阅以下文章:


什么是
commandwrapper.WrapCommand
?它是
子流程.popen的包装。我在上面的
pip
包中添加了链接。感谢您指出out.OSX和OSX中的默认终端(我认为这是
bash
?)。我可能想在您的问题中添加这一点,我无法使用bash在ubuntu上复制,
echo$0
将在linux上显示shell名称,实际上它可能适用于mac,请注意,它在任何地方都不能正常工作,包括pycharm,我得到了运行
ls
的部分文件,这太棒了。谢谢:-)没问题,不用客气。如果
print(cmd.stdout.readlines())
在while循环之外,您将看到剩余的/所有的输出,因为数据正在被缓冲,而不管是否刷新