实时输出subprocess.popen()而非逐行输出

5 投票
3 回答
6394 浏览
提问于 2025-04-16 09:32

我现在正在用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++那样?

3 个回答

0

抱歉,我对实时部分不是很理解,不过也许我可以帮你解决“自己更新”的部分,试试这个:

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

在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系统上,似乎可以通过写回车符来重置光标的位置。可以参考一下如何擦除当前打印的控制台行在终端或控制台中进行就地进度输出

7

可能有两个原因...

很可能是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()

必须执行flush操作,因为标准输出会缓存内容,直到遇到\n,而你当然没有写这个。

撰写回答