К 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()