Очистка Python Popen

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

Я перехожу к модулю подпроцесса и пробую:

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

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

 grep: writing output: Broken pipe 

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

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

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

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

Предупреждение Это будет заторможен, если дочерний процесс генерирует достаточный вывод в канал stdout или stderr, так что он блокирует ожидание буфера для буфера OS, чтобы принимать больше данных. Используйте 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) не поможет вам:

Предупреждение Используйте .stdin.write 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: loop, но приведенное выше предупреждение указывает на то, что это может 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() 
Interesting Posts