Я хотел использовать Python, эквивалентный передаче по каналу некоторых команд оболочки в жемчуге. Что-то как версия Python открытых (КАНАЛ, "управляют |").
Я перехожу к модулю подпроцесса и пробую это:
p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE)
Это работает на чтение вывода тем же путем, я был бы в жемчуге, но это не моется. Когда я выхожу из интерпретатора, я добираюсь
grep: writing output: Broken pipe
извергнутый на всем протяжении stderr несколько миллионов раз. Я предполагаю, что наивно надеялся, что все это будет заботиться о для меня, но это не верно. Оконечный вызов или уничтожает на p, кажется, не помогает. Посмотрите на таблицу процессов, я вижу, что это уничтожает процесс/bin/sh, но оставляет дочерний gzip на месте для жалобы на поврежденный канал.
Что правильный путь состоит в том, чтобы сделать это?
Проблема в том, что канал
заполнен. Подпроцесс останавливается, ожидая опустошения канала, но затем ваш процесс (интерпретатор 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
. Этот должен избегать взаимоблокировок, но, учитывая противоречивые предупреждения выше, кто знает .
В любом случае, если эта последняя часть у вас не работает (хотя она должна ), вы можете попробовать создать временный файл, записав в него все данные из первого вызова, а затем используя временный файл в качестве входных данных для следующего процесса.
Вам нужно подождать
завершения процесса:
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()
Как вы выполнили этот процесс?
Правильный способ - использовать
p.communicate()
Подробнее см. В документации.
После открытия канала вы можете работать с выводом команды: p.stdout
:
for line in p.stdout:
# do stuff
p.stdout.close()