2015-01-21 5 views
2

Сценарий: PCAP файл сжат с BZIP2, что я хотел бы проанализировать с tcpdump и перечислить результаты по строкам, в пределах Python 2.7. Вот что я придумал с верхней части моей головы:Как распаковать BZ2 непосредственно в Popen stdin в Python 2.7?

def tcpdump(filename): 
    import subprocess 
    import bz2 

    p = subprocess.Popen(
     ('tcpdump', '-lnr', '-s', '0', '-'), 
     stdin=bz2.BZ2File(filename), 
     stdout=subprocess.PIPE) 

    try: 
     for row in p.stdout: 
      yield row.rstrip() 
    except KeyboardInterrupt: 
     p.terminate() 

Проблема с этим состоит в том, что параметр Popenstdin ожидает фактический дескриптор файла и выдает это исключение:

AttributeError: «bz2 .BZ2File 'объект не имеет атрибута' fileno '

Я мог бы легко сделать это двухэтапным процессом, но я бы хотел избежать промежуточного временного файла.

Мысли или предложения?

+0

Совсем в стороне от bzip2, 'Popen (('tcpdump', '-l -n -s 0 -r -'))' такой же, как 'tcpdump '-l -n -s 0 -r - "', который также не будет работать в командной строке; вы не можете передать все свои несвязанные параметры в один большой аргумент. –

+0

@CharlesDuffy Спасибо - исправлено! –

ответ

2

Использование двух различных POPEN объектов:

p1 = subprocess.Popen(['bunzip2', '-c', filename], 
    stdout=subprocess.PIPE) 
p2 = subprocess.Popen(['tcpdump', '-lnr', '-s', '0', '-'], 
    stdin=p1.stdout, 
    stdout=subprocess.PIPE) 
p1.stdout.close() 
for row in iter(p2.stdout.readline, b''): 
    ... 
1

Чтобы избежать bunzip2 зависимость, можно накачать ввод вручную:

import subprocess 
import threading 
from contextlib import closing 

p = subprocess.Popen(['tcpdump', '-lnr', '-s', '0', '-'], 
        stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=-1) 
threading.Thread(target=pump, args=[filename, p.stdin]).start() 
with closing(p.stdout): 
    for line in iter(p.stdout.readline, b''): 
     print line, 
p.wait() 

где pump() является:

from shutil import copyfileobj 

def pump(filename, pipe): 
    """Decompress *filename* and write it to *pipe*.""" 
    with closing(pipe), bz2.BZ2File(filename) as input_file: 
     copyfileobj(input_file, pipe)