python - 包装子进程的标准输出/标准错误

标签 python subprocess stdout iostream stderr

我想捕获和显示我通过 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 的东西,它们有 self 更新的进度,而无需每次都写入新行。

更新2

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

最佳答案

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

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

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

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

关于python - 包装子进程的标准输出/标准错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4335587/

相关文章:

python - 无法使用具有身份文件的子进程进行 SSH

bash - 将 bash time 命令的输出加载到变量

python - AWS EC2 Django runserver 端口 8000 出现问题

python - 使用 tkinter 将文件路径从浏览按钮放入全局变量中

python - 子进程无法使用 Pandas 执行文件

subprocess - 使用 subprocess.check_output Python 的环境变量

linux - 如何将输出重定向到文件和标准输出

ruby - 在 irb (ruby) 中截断 #inspect 输出

python - sqlalchemy - 如何复制深复制条目及其所有外部关系

python - 如果在类型列表的单元格值中找到字符串,如何根据条件删除 pandas 数据框中的行?