我想从我正在推出的C程序中捕获输出:
p = subprocess.Popen(["make", "run_pci"],
stdout=subprocess.PIPE,
cwd="/home/ecorbett/hello_world_pthread")
for ln in p.stdout:
唯一的问题是我在C程序完成之前不会输出,实际上我需要在程序运行时逐行输出。更复杂的是,我必须解析每一行(我只需要来自行的某些数据)。
例如,这里有一些示例输出:(我需要捕获“Thread on Tile#”)
blahblah blah Thread blahblah blah tile 1: On
blahblah blah Thread blahblah blah tile 2: OFF
blahblah blah Thread blahblah blah tile 3 : Disable
我注意到我在下面链接的文章似乎有同样的问题。我试图弄清楚如何使其适应我的情况?
Getting realtime output from ffmpeg to be used in progress bar (PyQt4, stdout)
Python新手,所以示例代码非常感谢!!!
答案 0 :(得分:3)
您需要使用pexpect
的原因是,如果程序的stdio未连接到tty,它将使用块缓冲。 pexpect
使用伪tty(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])))
答案 1 :(得分:2)
你不能像那样使用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"
最好将stdout设置为行缓冲(通常尽可能完全缓冲),但我认为这只能在被调用的程序中完成。
我们在这里要考虑两个缓冲区。一个是C程序的输出缓冲区。这可能是不存在的(无缓冲输出),线路缓冲或完全缓冲(1K,4K或8K是一些可能的大小)。
在程序中,调用“printf()”。输出结果如下:
现在输出进入Python的管道。这也可以是完全缓冲(stdout)或行缓冲(readline)。所以输出结果如下:
在最后一种情况下,缓冲区将以4K块的形式传入Python逻辑。
现在让我们想象一个行缓冲 C程序向Python程序输出一行,每行1K个字符(如果C程序完全缓冲,那么可能不是很多完成!)
在循环中读取stdout,我们会看到(在for循环中):
通过readline阅读我们会得到:
示例强>
这里我运行“ping -c 3 -i 2 127.0.0.1”以便以两秒的间隔将三个数据包发送到localhost。一次ping操作大约需要6秒钟。我从ping读取输出,并打印时间戳。 ping的整个输出足够小,以至于它适合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