3

之前,我问过这个问题:

如何使用本机 python 执行 ping 或 traceroute?

但是,由于 python 不是以 root 身份运行的,因此它无法打开在本机 python 中执行 ping/traceroute 所需的原始 ICMP 套接字。

这让我回到了使用系统的 ping/traceroute shell 命令。这个问题有几个使用该subprocess模块的示例,这些示例似乎运行良好:

用 Python ping 一个站点?

不过,我还有一个要求:我需要能够在输出生成时访问它(例如,对于长时间运行的跟踪路由。)

上面的示例都运行 shell 命令,然后只有在命令完成后才能访问完整的输出。有没有办法在生成命令输出时访问它?

编辑:根据 Alex Martelli 的回答,以下是有效的:

import pexpect

child = pexpect.spawn('ping -c 5 www.google.com')

while 1:
        line = child.readline()
        if not line: break
        print line,
4

4 回答 4

6

pexpect是我“默认情况下”针对您的任何要求所达到的要求——还有其他类似的模块,但 pexpect 几乎总是最丰富、最稳定和最成熟的模块。我会费心寻找替代方案的一种情况是,如果我也必须在 Windows 下正确运行(无论如何,ping 和 traceroute 可能有它们自己的问题)——让我们知道你是否是这种情况,我们会看看可以安排什么!-)

于 2009-07-20T06:05:33.053 回答
5

您应该阅读subprocess模块的文档,它描述了如何运行外部进程并实时访问其输出。

基本上,你会

from subprocess import Popen, PIPE
p = Popen(['tracert', host], stdout=PIPE)
while True:
    line = p.stdout.readline()
    if not line:
        break
    # Do stuff with line

实际上,您链接到的 SO 问题中的答案非常接近您的需要。Corey Goldberg 的答案使用管道和readline,但由于它运行 ping-n 1并不会持续足够长的时间来产生影响。

于 2009-07-20T06:08:39.193 回答
1

您可以为子进程创建一个 tty 对并在其中运行。根据 C 标准(C99 7.19.3),stdout 唯一一次被行缓冲(而不是你说你不想要的完全缓冲)是当它是一个终端时。(或显然称为 setvbuf() 的孩子)。

查看 os.openpty()。

未经测试的代码:

master, slave = os.openpty()
pid = os.fork()
if pid == 0:
    os.close(master)
    os.dup2(slave, 0)
    os.dup2(slave, 1)
    os.dup2(slave, 2)
    os.execv("/usr/sbin/traceroute", ("traceroute","4.2.2.1"))
    # FIXME: log error somewhere
    os.exit(1)
os.close(slave)
while True:
    d = os.read(master)
    if len(d) == 0:
        break
    print d
os.waitpid(pid, 0)

请注意,让子进程(就在 fork() 之后)调用 setvbuf() 将不起作用,因为 setvbuf() 是 libc 函数而不是系统调用。它只是改变当前进程输出的状态,当加载新的二进制文件时,它将在 exec 调用中被覆盖。

于 2009-07-20T06:32:52.483 回答
1

这是另一种方法:

# const_output.py
import sys
from subprocess import Popen

if len(sys.argv) < 2:
    print 'Usage: const_output.py "command to watch"'
    sys.exit(1)

cmd_line = sys.argv[1:]

p = Popen(cmd_line)
p.communicate()[0]

示例用法:

跟踪路由:

> python const_output.py traceroute 10.0.0.38
traceroute to 10.0.0.38 (10.0.0.38), 30 hops max, 60 byte packets
 1  10.0.0.38 (10.0.0.38)  0.106 ms  0.023 ms  0.021 ms

平:

> python const_output.py ping 10.0.0.38
PING 10.0.0.38 (10.0.0.38) 56(84) bytes of data.
64 bytes from 10.0.0.38: icmp_seq=1 ttl=64 time=0.046 ms
64 bytes from 10.0.0.38: icmp_seq=2 ttl=64 time=0.075 ms
64 bytes from 10.0.0.38: icmp_seq=3 ttl=64 time=0.076 ms
64 bytes from 10.0.0.38: icmp_seq=4 ttl=64 time=0.073 ms

最佳:

> python const_output.py top
   # you will see the top output
于 2013-11-12T13:35:23.567 回答