К popen очистки в Python

Я хотел использовать python, эквивалентный передаче некоторых команд оболочки в perl. Что-то вроде версии Python open(PIPE, "command |").

Я иду в модуль подпроцесса и пробую это:

p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE)

это работает для чтения вывода так же, как и в perl, но он не очищается. Когда я выхожу из переводчика, я получаю

grep: writing output: Broken pipe

извергли по всему stderr несколько миллионов раз. Наверное, я наивно надеялся, что обо всем этом позаботятся. для меня, но это не правда. Вызов terminate или kill на p, похоже, не помогает. Посмотрите на таблицу процессов, я вижу, что это убивает процесс /bin/sh, но оставляет дочерний gzip на месте, чтобы жаловаться на сломанную трубу.

Как правильно это сделать?

4 ответов


проблема в том, что pipe полно. Подпроцесс останавливается, ожидая, пока канал опустеет, но затем ваш процесс (интерпретатор Python) завершается, ломая его конец канала (отсюда сообщение об ошибке).

p.wait() не поможет вам:

предупреждение это приведет к взаимоблокировке, если дочерний процесс генерирует достаточно выходных данных в канал stdout или stderr, так что он блокирует ожидание буфера канала ОС, чтобы принять больше данных. Использовать communicate() избегать этого.

http://docs.python.org/library/subprocess.html#subprocess.Popen.wait

p.communicate() не поможет вам:

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

http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate

p.stdout.read(num_bytes) будет не помочь вам:

предупреждение использовать communicate(), а не .stdin.write, .stdout.read или .stderr.read чтобы избежать блокировок из-за любого другого буфера трубы ОС, заполняющего и блокирующего дочерний процесс.

http://docs.python.org/library/subprocess.html#subprocess.Popen.stdout

мораль истории, для большого выхода,subprocess.PIPE обречет вас на определенный провал, если ваша программа пытается прочитать данные (мне кажется, что вы должны уметь ставить p.stdout.read(bytes) на while p.returncode is None: цикл, но вышеупомянутое предупреждение предполагает, что это может привести к взаимоблокировке).

врачи предлагают заменить оболочку трубы с этого:

p1 = Popen(["zgrep", "thingiwant", "largefile"], stdout=PIPE)
p2 = Popen(["processreceivingdata"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

обратите внимание, что p2 принимает свой стандартный входной сигнал сразу от p1. Это должны избегайте тупиков, но учитывая противоречивые предупреждения выше,кто знает.

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


после открытия трубы, вы можете работать с вывода команды: p.stdout:

for line in p.stdout:
    # do stuff
p.stdout.close()

Как вы выполнили этот процесс?

правильный способ-использовать

p.communicate()

дополнительные сведения см. В документах.


вам нужно wait для завершения процесса:

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True)
p.wait()

кроме того, вы можете захватить стандартный вывод программы (как у вас есть) и, возможно, ее стандартную ошибку, а затем вызвать communicate:

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True,
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()