【问题标题】:Real time output of subprocess.popen() and not line by linesubprocess.popen() 的实时输出而不是逐行输出
【发布时间】:2011-01-06 22:16:59
【问题描述】:

我目前正在用 python 重写一个我曾经用 C++ 编写的小包装程序。它从文件中提取文件并以另一种格式将它们装箱。

在 C++ 中,我需要运行的系统命令的输出是“实时”的,即实时显示的状态栏和某些命令的百分比指示器。使用python,我将每个“百分比”单独转储到屏幕上(因为我逐行阅读)。这是一个示例:这就是状态栏在 python 版本中的外观(一直持续到 100)。但在 C++ 中,它确实会自行更新。

| (02/100)\rImporting AVC-H264: |                    | (03/100)\rImporting AVC-H264: |                       | (04/100)\rImporting AVC-H264: |=

就是对应的python代码:

p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
for line in iter(p.stdout.readline, ""):
   print line,

关于如何使它看起来像 C++ 的任何想法?

【问题讨论】:

    标签: python subprocess popen


    【解决方案1】:

    可能是两件事......

    很可能 readline 正在更改您的输出中的某些内容 程序。我相信\r 是回车并告诉终端 回到开头 行,然后程序可以在它刚刚输出的文本之上输出。 Readline 很可能会删除它。

    首先要尝试,

    p = subprocess.Popen(args, stdout=subprocess.PIPE, \
                         stderr=subprocess.PIPE, \
                         universal_newlines=True)
    for line in iter(p.stdout.readline, ""):
        sys.stdout.write('\r'+line[:-1])
        sys.stdout.flush()
    

    必须进行刷新,因为 stdout 会缓冲,直到它获得 \n 和 当然你不是在写。

    【讨论】:

    • 感谢您的所有回答。我玩弄这个解决方案,我认为它必须是这样的:while 1: data = p.stdout.read() sys.stdout.write(data) # process is done so break if p. returncode is not None: break 问题是现在它会一次将所有内容都转储到屏幕上,但在彼此之下,它仍然不会覆盖自己。我很难理解 p.stdout.read() 返回的内容。它在什么时候决定“这就是我要返回的东西”?
    • p.stdout.read() 将从标准输出读取该管道上可用的任何和所有数据。我已经编辑了我的解决方案。试一试,让我知道什么不起作用。
    • 感谢您的帮助!现在效果更好,线条不再显示在彼此下方。现在发生的情况是,我看到命令输出的前两行和下面的空间(“进度:(百分比)”应该是空的。命令完成后,“进度:100%”就会打印在那里。我认为这与缓冲区有关。如果我省略 'sys.stdout.flush()' 没有区别。如果您需要更详细的信息,请告诉我。
    • 嘿,我发布了一个适用于我构建的演示的解决方案。基本上,似乎readlineread 都没有处理这些行,因为它没有将\r 识别为换行符。它说输出是无缓冲的,但是 已经 有一些缓冲正在进行,我可以说我不完全理解(并且在不同的系统上可能会有所不同)。试一试,让我知道。
    • @Basil:删除stderr=PIPE。设置stderr=STDOUTstderr=DEVNULL。除非您从流中读取,否则不要使用 PIPE。否则,如果相应的 OS 管道缓冲区填满,子进程可能会挂起。此外,您应该使用line.rstrip('\n') 而不是line[:-1],以防输出末尾没有换行符。即使您使用bufsize=1,缓冲问题也可能不会结束,请参阅Python C program subprocess hangs at “for line in iter”
    【解决方案2】:

    在 Windows 上,您可以输出退格字符(ASCII 代码 8)。示例(仅使用单个数字打印当前迭代):

    >>> import time
    >>> import sys
    >>> for i in xrange(10):
    ...     sys.stdout.write(str(i))
    ...     time.sleep(.5)
    ...     sys.stdout.write(chr(8))
    ...
    

    您需要跟踪当前行的字符数...我相信一定有更好的方法。

    在 Linux 上,您似乎可以写回车来重置光标位置。请参阅Erase the current printed console lineIn-place progress output in the terminal or console

    【讨论】:

    • 我认为您可以在不知道字符数的情况下逃脱,因为据我所知,父进程的输出始终是相同的长度。
    【解决方案3】:

    对不起,我不太了解实时部分,但也许我可以帮助“自我更新”部分,试试这个:

    for line in iter(p.stdout.readline, ""):
       print line + '\r',
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-07
      • 1970-01-01
      • 1970-01-01
      • 2016-01-10
      • 2014-10-25
      • 1970-01-01
      • 2018-02-23
      相关资源
      最近更新 更多