Попон очистка Python - PullRequest
       23

Попон очистка Python

7 голосов
/ 08 апреля 2010

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

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

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

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

grep: writing output: Broken pipe

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

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

Ответы [ 4 ]

9 голосов
/ 09 апреля 2010

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

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

3 голосов
/ 08 апреля 2010

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

for line in p.stdout:
    # do stuff
p.stdout.close()
0 голосов
/ 09 апреля 2010

Вам нужно 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()
0 голосов
/ 08 апреля 2010

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

Правильный способ использования

p.communicate()

См. Документы для более подробной информации.

...