Очистка Python Popen

Я хотел использовать Python, эквивалентный передаче по каналу некоторых команд оболочки в жемчуге. Что-то как версия Python открытых (КАНАЛ, "управляют |").

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

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

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

grep: writing output: Broken pipe

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

Что правильный путь состоит в том, чтобы сделать это?

7
задан pythonic metaphor 7 April 2010 в 20:14
поделиться

4 ответа

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

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

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

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) вам не поможет:

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

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

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

В документации предлагается заменить оболочку оболочки следующим образом:

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

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

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

9
ответ дан 6 December 2019 в 21:11
поделиться

Вам нужно подождать завершения процесса:

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

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

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True,
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
0
ответ дан 6 December 2019 в 21:11
поделиться

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

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

p.communicate()

Подробнее см. В документации.

0
ответ дан 6 December 2019 в 21:11
поделиться

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

for line in p.stdout:
    # do stuff
p.stdout.close()
3
ответ дан 6 December 2019 в 21:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: