Использование subprocess и pipes в Python: метод check_output()

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для создания в Python цепочки команд можно использовать subprocess.Popen. Если вы хотите перенаправить стандартный вывод одной команды как вход для другой, используйте stdout=subprocess.PIPE. Ниже приведен код, который выполняет ту же операцию, что и ls | grep py в терминале:

Python
Скопировать код
from subprocess import Popen, PIPE

# Стандартный вывод команды 'ls' передается на вход 'grep'
ls = Popen(['ls'], stdout=PIPE)
grep = Popen(['grep', 'py'], stdin=ls.stdout, stdout=PIPE)

ls.stdout.close()  # Закрываем вывод 'ls'
output, _ = grep.communicate()  # Получаем результат

print(output.decode())

Здесь Popen формирует пайплайн команд, а communicate() служит для получения конечного результата.

Кинга Идем в IT: пошаговый план для смены профессии

Игры с оболочкой: Когда использовать shell=True

Параметр shell=True пригодится, если вам требуются возможности оболочки, такие как пайпы или перенаправление. Однако берегитесь: всегда проверяйте входные данные, чтобы избежать уязвимостей:

Python
Скопировать код
import subprocess

# Пайп команд через оболочку
output = subprocess.check_output('ls | grep py', shell=True)

print(output.decode('utf-8'))

Использовать shell=True стоит аккуратно, особенно если данные непроверенны.

Привлекательная эффективность с subprocess.run

subprocess.run() — это современный и удобный способ выполнения подпроцессов, который сразу предоставляет результаты:

Python
Скопировать код
import subprocess

result = subprocess.run(['grep', 'py'], capture_output=True, text=True)
print(result.stdout)

Про обработку исключений при ошибке выполнения команды позаботится параметр check=True: при любом неполадках он вызовет исключение:

Python
Скопировать код
try:
    subprocess.run(['false'], check=True)
except subprocess.CalledProcessError:
    print("Ой-ой, Хьюстон, у нас проблема.")

Обработка вывода как профессионал

Чтобы преобразовать байтовые данные в строки, используйте метод .decode():

Python
Скопировать код
output = subprocess.run(['ls'], stdout=subprocess.PIPE).stdout
print(output.decode('utf-8'))

Также удобен метод .communicate(), помогающий избежать проблем, связанных с stdout и stderr, предотвращая блокировки:

Python
Скопировать код
from subprocess import PIPE, Popen

proc = Popen(['your_cmd'], stdout=PIPE, stderr=PIPE)
stdout, stderr = proc.communicate()

Переход между множеством процессов

При работе с несколькими подпроцессами важно правильно управлять потоками данных. Не забывайте закрывать stdout команды, которую более не используете:

Python
Скопировать код
from subprocess import Popen, PIPE

ps = Popen(['ps', '-A'], stdout=PIPE)
grep = Popen(['grep', 'process_name'], stdin=ps.stdout, stdout=PIPE)
ps.stdout.close()  # Закрываем вывод 'ps'

output = grep.communicate()[0]
print(output.decode('utf-8'))

Упрощаем жизнь с sh.py

Модуль sh значительно упрощает работу с подпроцессами. Установите его через pip install sh и контролируйте процессы, как если бы вы писали обычные команды:

Python
Скопировать код
from sh import grep, ps

# Имитация команды 'ps -ax | grep process_name'
print(grep(ps("-ax"), "process_name"))

Изюминки в работе с subprocess

Работа со subprocess требует внимательности и точности, как и при создании гастрономических шедевров:

  • Берегитесь переполнения буфера — слишком большой вывод может вызвать проблемы.
  • Будьте аккуратны с переменными окружения при использовании shell=False.
  • Не забывайте "убирать посуду" — убедитесь, что все "кастрюли" (пайпы) закрыты, чтобы избежать проблем с завершением процессов.

Визуализация

Работа в subprocess, нацеленная на создание пайплайна, похоже на строителя, передающего кирпичи для постройки здания:

Markdown
Скопировать код
`cmd1` 🔧 | `cmd2` 🔨 | `cmd3` 🛠️

Каждый символ | символизирует передачу "кирпича" (данных) от одного инструмента к другому.

Python
Скопировать код
import subprocess
result = subprocess.run('cmd1 | cmd2 | cmd3', shell=True, text=True, stdout=subprocess.PIPE)

Каждый шаг строительства приводит к завершению сооружения "здания" данных.

Безопасность – дело серьезное

Продумайте меры безопасности, когда работаете с подпроцессами, особенно когда используете shell=True:

  • Проверяйте данные на предмет возможных уязвимостей.
  • По возможности старайтесь обходиться без shell=True.
  • Для безопасной обработки пользовательского ввода, предназначенного для shell=True, используйте shlex.split.

Как стать опытным мастером

Несколько советов, чтобы ваша работа с subprocess была стабильной и высокопроизводительной:

  • Для простых задач используйте run с capture_output=True или stdout=PIPE.
  • Для больших проектов вы можете записывать данные в файл или обрабатывать их пакетами.
  • Сложные пайплайны лучше управлять, создавая непосредственно объекты Popen.

Дополнительные советы и хитрости для опытного строителя

Чтобы добиться мастерства в работе с subprocess:

  • Используйте контекстные менеджеры для более удобного управления процессами.
  • Объединяйте stdout и stderr, используя stderr=subprocess.STDOUT.
  • Изучите использование возвращаемых кодов для контроля за успешностью выполнения команд.

Полезные материалы

  1. subprocess — Управление подпроцессами — Документация Python 3.12.2 — официальная документация по управлению подпроцессами.
  2. Модуль subprocess: Оболочка программ Python – Real Python — полезный обзор, как лучше всего использовать subprocess.
  3. python – Как использовать команду subprocess с пайпами – Stack Overflow — примеры и обсуждение использования пайпов.
  4. Python Pipes для избежания оболочек — Документация советов безопасности OpenStack 0.0.1.dev265 — информация о проблемах безопасности при использовании shell=True.
  5. shlex — Простой лексический анализ — Документация Python 3.12.2 — руководство по использованию shlex для безопасного разделения ввода.