在使用Python子进程的stdout捕获来自C程序的输出? Pexpect的?(Capture

2019-06-26 09:42发布

我想从一个C程序,我推出这样的捕获输出:

p = subprocess.Popen(["make", "run_pci"],
                     stdout=subprocess.PIPE,
                     cwd="/home/ecorbett/hello_world_pthread")
for ln in p.stdout:

唯一的问题是我不明白输出,直到C程序完成,但实际上我需要一线得到输出线作为程序运行。 而对于更复杂的问题,我必须分析每一行(我只是从线需要一定的数据)。

例如,下面是一些示例输出:(我需要捕捉“关于瓷砖#主题”)

blahblah blah Thread blahblah blah tile 1: On 
blahblah blah Thread blahblah blah tile 2: OFF 
blahblah blah Thread blahblah blah tile 3 : Disable

我发现我下面链接的文章似乎有同样的问题。 我试图找出如何使它适应我的情况?

获得从FFMPEG实时输出到在进度条中使用(PyQt4中,由于输出)

蟒新手,所以例如代码是极大的赞赏!

Answer 1:

您不能使用p.stdout那样; 如果你问“全标准输出”,这只会是可利用的进程终止(或管道缓冲区填充,这可能需要很长的时间)。

你需要从线进程的标准输出线阅读。

while True:
    ln = p.stdout.readline()
    if '' == ln:
        break
    m = re.search("Thread (?P<id>\d+)", ln);
    if m:
        # use m.group() to extract information
        # e.g. m.group('id') will hold the 12345 from "Thread 12345"

这也将是最好的,如果标准输出可以设置为行缓冲(通常是全缓冲尽可能),但我认为这只能从被调用的程序中完成的。

我们有两个缓冲区来考虑这里。 一个是C程序的输出缓冲区。 这可能是不存在的(未缓冲的输出),行缓冲,或全缓冲(1K,4K或8K是一些可能的尺寸)。

在节目中,“的printf()”之称。 输出变为:

  • 出,如果缓冲
  • 入缓冲器中; 然后在缓冲器中的所有换行符 - 封端的行被输出,如果行缓冲;
  • 入缓冲器中; 然后第一4K被输出,如果与4K缓冲器全缓冲以及缓冲大于4K更充分。

现在输出进入Python的管道。 这再次可以充分缓冲(标准输出)或行缓冲(readline的)。 所以输出变为:

  • 到Python程序的逻辑,如果有在管道中一个完整的换行符终止行,我们使用的ReadLine
  • 到缓冲区中,如果有不足4K的管道,我们使用“在标准输出LN”。

在后一种情况下,缓冲区将在4K块去Python的逻辑。

现在让我们设想一个缓冲行的C程序输出一行,1K个字符,每一个第二,一个Python程序(如C程序是完全缓冲的,有没有很多可以做!)

在循环阅读的stdout,我们将看到(里面的for循环):

  • T = 0 ...什么都没有
  • T = 1 ...没有(缓冲液是50%满)
  • T = 2 ...没有(缓冲液是75%满)
  • T = 3 ...四行输出的
  • T = 4 ...什么... ...

通过readline的,我们将得到阅读:

  • T = 0 ...一行
  • T = 1 ...一行
  • T = 2 ...一个线
  • T = 3 ...一行

在这里,我为了得到三个数据包在两个秒的间隔运行本地主机的“ping -c 3 -i 2 127.0.0.1”。 平的一个运行大约需要六秒钟。 我读了平的输出,打印时间戳。 平的整个输出是足够小,它适合于Python的全缓冲。

#!/usr/bin/python

import subprocess
from time import gmtime, strftime

p = subprocess.Popen(["ping", "-c", "3", "-i", "2", "127.0.0.1"],
                 stdout=subprocess.PIPE)

for ln in p.stdout:
    print strftime("%H:%M:%S", gmtime()) + " received " + ln

# Now I start the same process again, reading the input the other way.

p = subprocess.Popen(["ping", "-c", "3", "-i", "2", "127.0.0.1"],
                 stdout=subprocess.PIPE)

while True:
    ln = p.stdout.readline()
    if '' == ln:
            break
    print strftime("%H:%M:%S", gmtime()) + " received " + ln

我收到我的Linux机器的输出,符合市场预期:

(nothing for the first six seconds)
15:40:10 received PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.037 ms
15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.034 ms
15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.031 ms
15:40:10 received
15:40:10 received --- 127.0.0.1 ping statistics ---
15:40:10 received 3 packets transmitted, 3 received, 0% packet loss, time 3998ms
15:40:10 received rtt min/avg/max/mdev = 0.031/0.034/0.037/0.002 ms

15:40:10 received PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
15:40:10 received 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.041 ms
15:40:12 received 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.039 ms
15:40:14 received 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.035 ms
15:40:14 received
15:40:14 received --- 127.0.0.1 ping statistics ---
15:40:14 received 3 packets transmitted, 3 received, 0% packet loss, time 3999ms
15:40:14 received rtt min/avg/max/mdev = 0.035/0.038/0.041/0.005 ms


Answer 2:

你需要使用的原因pexpect是该程序的标准输入输出将使用块缓冲,如果它没有连接到一个tty。 pexpect使用伪终端(PTY)这样的stdio将使用行缓冲,您将能够为他们输出访问线。

更改您的代码:

p = pexpect.spawn('make', ['run_pci'], cwd="/home/ecorbett/hello_world_pthread")
for ln in p:
    ...

您可以使用pexpect.spawn.expect只得到你感兴趣的输出:

while p.expect('Thread on Tile (\d+):', pexpect.EOF) == 0:
    print("Tile {0}".format(int(p.group[1])))


文章来源: Capture output from C program on stdout using Python subprocess? Pexpect?