Как использовать команду `subprocess` с каналами

246

Я хочу использовать subprocess.check_output()с ps -A | grep 'process_name'. Я пробовал разные решения, но пока ничего не получалось. Кто-нибудь может подсказать мне, как это сделать?

zuberuber
источник
4
есть psutilто, что позволяет получать информацию о процессе в портативном виде.
Jfs

Ответы:

440

Чтобы использовать трубу с subprocessмодулем, нужно пройти shell=True.

Однако это не рекомендуется по разным причинам, не в последнюю очередь из-за безопасности. Вместо этого, создать psи grepпроцессы по отдельности, а труба на выходе одного из в другой, например , так:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

В вашем конкретном случае, однако, простое решение состоит в том, чтобы позвонить, subprocess.check_output(('ps', '-A'))а затем str.findна выходе.

Taymon
источник
82
+1 за разделение вывода / ввода, чтобы избежать использованияshell=True
Nicolas
5
Не забывайте, ошибка subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1просто означает, что grep ничего не нашел, так что это нормальное поведение.
Серж
2
Зачем нам нужно, ps.wait()когда у нас уже есть выход. ps.wait.__doc__ждет, когда ребенок завершит свою работу, но содержание ребенка, кажется, уже помещено в outputпеременную
Папуш Гуинслизиньо
3
@MakisH Вы смотрите string.find, который устарел в пользу str.find(то есть, метод findна strобъектах).
Таймон
4
примечание: если grepумирает преждевременно; psможет зависать на неопределенный срок, если он выдает достаточно данных, чтобы заполнить свой буфер канала ОС (потому что вы не вызвали ps.stdout.close()родительский буфер ). Поменяйте местами стартовый порядок, чтобы избежать этого
JFS
54

Или вы всегда можете использовать метод связи для объектов подпроцесса.

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

Метод связи возвращает кортеж стандартного вывода и стандартную ошибку.

jkalivas
источник
3
Я думаю, что использование communicateлучше, чем wait. Существует такое предупреждение: «Это приведет к взаимоблокировке при использовании stdout = PIPE и / или stderr = PIPE, и дочерний процесс генерирует достаточно данных для канала, так что он блокирует ожидание буфера канала ОС для приема большего количества данных. Используйте Communication () для избегай этого.
Паоло
2
Чтобы пояснить комментарий Паоло выше, предупреждение предназначено для ожидания, а не для общения - то есть по этой причине он говорит, что общение лучше.
EnemyBagJones
23

См. Документацию по настройке конвейера с использованием подпроцесса: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline.

Я не тестировал следующий пример кода, но он должен быть примерно таким, как вы хотите:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]
пузырь алькубьерра
источник
2
После проверки этого провала, посмотрите ответ Taymon ниже для чего-то, что работает без раздумий
Alvin
2
subprocess.check_output не существует в Python 2.6.9
RightmireM
6

Решение JKALAVIS хорошо, однако я бы добавил улучшение для использования shlex вместо SHELL = TRUE. ниже я вытащил время запроса

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)
Даниэль Смит
источник
1
Почему Shellx над оболочкой?
AFP_555
2
где здесь используется шлекс?
3lok
4

Кроме того, попробуйте использовать 'pgrep'команду вместо'ps -A | grep 'process_name'

Shooe
источник
2
если вы хотите получить идентификатор процесса, очевидно
Shooe
3

Вы можете попробовать функциональность канала в sh.py :

import sh
print sh.grep(sh.ps("-ax"), "process_name")
amoffat
источник
-1

После Python 3.5 вы также можете использовать:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

Выполнение команды блокируется, и вывод будет в process.stdout .

zingi
источник