Как я могу выполнить ping или traceroute в python, получая доступ к выводу по мере его создания? - PullRequest
3 голосов
/ 20 июля 2009

Ранее я задавал этот вопрос:

Как я могу выполнить ping или traceroute, используя собственный питон?

Однако, поскольку python не работает от имени пользователя root, он не имеет возможности открывать необработанные сокеты ICMP, необходимые для выполнения команды ping / traceroute на нативном python.

Это возвращает меня к использованию системных команд оболочки ping / traceroute. В этом вопросе есть несколько примеров использования модуля subprocess, которые, кажется, работают хорошо:

Пинговать сайт на Python?

У меня все еще есть еще одно требование: мне нужно иметь доступ к выводу по мере его создания (например, для длительной трассировки).

Все вышеприведенные примеры запускают команду оболочки и дают вам доступ к полному выводу только после завершения команды. Есть ли способ получить доступ к выводу команды, как она создается?

Редактировать: Основываясь на ответе Алекса Мартелли, вот что сработало:

import pexpect

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

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

Ответы [ 4 ]

6 голосов
/ 20 июля 2009

pexpect - это то, чего я бы достиг, «по умолчанию», для любых требований, таких как у вас - есть другие подобные модули, но pexpect почти всегда является самым богатым, наиболее стабильным и наиболее зрелый. Единственный случай, когда я потрудился бы искать альтернативы, был бы, если бы мне пришлось работать правильно и под Windows (в любом случае ping и traceroute могут иметь свои проблемы) - дайте нам знать, если это так, и мы посмотри что можно устроить! -)

4 голосов
/ 20 июля 2009

Вы должны прочитать документацию для модуля подпроцесс , в которой описано, как запустить внешний процесс и получить доступ к его выходу в режиме реального времени.

В основном, вы делаете

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 очень близки к тому, что вам нужно. В ответе Кори Голдберга используется труба и readline, но, поскольку он запускает ping с -n 1, он не длится достаточно долго, чтобы что-то изменить.

1 голос
/ 12 ноября 2013

Вот еще один подход:

# 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
1 голос
/ 20 июля 2009

Вы можете создать пару tty для подпроцесса и запустить внутри нее. Согласно стандарту C (C99 7.19.3) единственный стандартный вывод - это буферизация строки (в отличие от полной буферизации, что, как вы говорите, вы не хотите), это когда это терминал. (или ребенок вызвал 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)

Обратите внимание, что при вызове setvbuf () дочернего процесса (сразу после fork ()) не будет работать, поскольку setvbuf () является функцией libc, а не системным вызовом. Он просто изменяет состояние текущего вывода процесса, который будет перезаписан при вызове exec при загрузке нового двоичного файла.

...