10

我想捕获和显示我通过 Python 的子进程调用的进程的输出。

我以为我可以将我的类文件对象作为命名参数 stdout 和 stderr 传递

我可以看到它访问了fileno属性 - 所以它正在对对象做一些事情。但是,该write()方法永远不会被调用。我的方法是完全关闭还是我只是错过了什么?

class Process(object):
    class StreamWrapper(object):
        def __init__(self, stream):
            self._stream = stream
            self._buffer = []
        def _print(self, msg):
            print repr(self), msg
        def __getattr__(self, name):
            if not name in ['fileno']:
                self._print("# Redirecting: %s" % name)
            return getattr(self._stream, name)
        def write(self, data):
            print "###########"
            self._buffer.append(data)
            self._stream.write(data)
            self._stream.flush()
        def getBuffer(self):
            return self._buffer[:]
    def __init__(self, *args, **kwargs):
        print ">> Running `%s`" % " ".join(args[0])
        self._stdout = self.StreamWrapper(sys.stdout)
        self._stderr = self.StreamWrapper(sys.stderr)
        kwargs.setdefault('stdout', self._stdout)
        kwargs.setdefault('stderr', self._stderr)
        self._process = subprocess.Popen(*args, **kwargs)
        self._process.communicate()

更新:

我也想使用 ANSI 控制字符来移动光标并覆盖以前的输出内容。我不知道这是否是正确的术语,但这是我的意思的一个例子:我正在尝试自动化一些 GIT 的东西,并且他们有自己更新的进度,而无需每次都写入新行。

更新 2

对我来说,立即显示子流程的输出很重要。我尝试使用 subprocess.PIPE 来捕获输出,并手动显示它,但我只能在进程完成后让它显示输出。但是,我想实时查看输出。

4

4 回答 4

12

进程的标准输入、标准输出和标准错误需要是真实的文件描述符。(这实际上不是 Python 施加的限制,而是管道在操作系统级别上的工作方式。)因此您将需要一个不同的解决方案。

如果您想实时跟踪两者,您将需要异步 I/O 或线程stdoutstderr

  • 异步 I/O:使用标准同步(=阻塞)I/O,对其中一个流的读取可能会阻塞,从而不允许实时访问另一个流。如果您在 Unix 上,则可以使用此答案中所述的非阻塞 I/O 。但是,在 Windows 上,您将无法使用这种方法。更多关于 Python 中的异步 I/O 和一些替代方法的信息在这个视频中展示。

  • 线程:处理此问题的另一种常见方法是为您要实时读取的每个文件描述符创建一个线程。线程只处理分配给它们的文件描述符,因此阻塞 I/O 不会造成伤害。

于 2010-12-02T14:15:13.137 回答
0

看看这里

p = subprocess.Popen(cmd,
                 shell=True,
                 bufsize=64,
                 stdin=subprocess.PIPE,
                 stderr=subprocess.PIPE,
                 stdout=subprocess.PIPE)
于 2010-12-02T13:42:47.550 回答
0

类似文件的距离不够近。它必须是具有实际文件描述符的实际文件。使用subprocess' 对管道的支持并根据需要从中读取。

于 2010-12-02T13:43:01.630 回答
-1

你在课堂上有一堂课是有原因的吗?并且 stdout 和 stderr 可以采用任何文件,例如 line 。所以简单地传递一个打开的文件类型或 stringIO 应该足以修改流

import sys
sys.stdout = open('test.txt','w')
print "Testing!"
sys.stdout.write('\nhehehe')
sys.stdout = sys.__stdout__
sys.exit(0)
于 2010-12-02T13:43:48.567 回答