Як використовувати команду `subprocess` з трубами


246

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



4
є psutilте, що дозволяє отримувати інформацію про процес портативно.
jfs

Відповіді:


439

Щоб використовувати трубу з 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на вихід.


81
+1 для розділення виходу / входу, щоб уникнути використанняshell=True
Nicolas

5
Не забувайте, помилка subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1просто означає, що греп нічого не знайшов, тому це нормальна поведінка.
Серж

2
Навіщо нам це потрібно, ps.wait()коли у нас вже є вихід. ps.wait.__doc__чекає, коли дитина припинить, але вміст дитини, здається, вже розміщений у outputзмінній
Papouche Guinslyzinho,

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)

Метод зв'язку повертає кордон стандартного виводу та стандартну помилку.


3
Я думаю, що використовувати communicateкраще, ніж wait. Існує таке попередження: "Це прийде в глухий кут при використанні stdout = PIPE та / або stderr = PIPE, і дочірній процес генерує достатній вихід на трубу, щоб заблокувати очікування, коли буфер труб ОС прийме більше даних. Використовуйте зв'язок () для уникати цього ".
Паоло

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
Перевіривши це не вдалося, див. Відповідь Таймона нижче про те, що працює, не замислюючись
Елвін

2
subprocess.check_output, здається, не існує в Python 2.6.9
RightmireM

6

Рішення JKALAVIS добре, проте я б додав поліпшення для використання shlex замість SHELL = ІСТИНА. нижче імпортування разів запитів

#!/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
Чому оболонка над оболонкою?
AFP_555

2
де тут використовується шлекс?
3лох

4

Також спробуйте використовувати 'pgrep'команду замість'ps -A | grep 'process_name'


2
якщо ви хочете отримати ідентифікатор процесу, очевидно
Shooe

3

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

import sh
print sh.grep(sh.ps("-ax"), "process_name")

-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 .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.