Home » Вызов системных команд в Python — модули os и subprocess
Вызов системных команд в Python — модули os и subprocess

Вызов системных команд в Python — модули os и subprocess

В этой статье разберёмся, как в Python вызывать системные команды через модули os и subprocess. Это не просто очередной туториал для новичков — речь пойдёт о реальных сценариях, когда нужно автоматизировать рутину на сервере, быстро интегрировать shell-скрипты в пайтонячий код, или просто сделать свою жизнь проще при настройке и обслуживании инфраструктуры. Если вы когда-нибудь писали скрипты для деплоя, мониторинга или резервного копирования, то знаете, насколько важно уметь грамотно дергать системные утилиты из Python. Здесь будет всё: как это работает, как настроить, что выбрать, где подводные камни, и как не наступить на грабли, на которые наступали тысячи раз до вас.

Как это работает?

Вызов системных команд из Python — это способ взаимодействовать с операционной системой на низком уровне, не выходя из любимого языка. По сути, вы можете запускать любые shell-команды, как если бы писали их в терминале, но делать это из Python-скрипта. Это открывает огромные возможности для автоматизации: от управления сервисами и файлами до интеграции с внешними инструментами и написания своих мини-утилит.

В Python для этого есть два основных инструмента:

  • os.system() и другие функции модуля os — старый, добрый, но уже не очень модный способ.
  • subprocess — современный, гибкий и безопасный модуль, который пришёл на смену os.system().

Оба модуля позволяют запускать внешние процессы, но делают это по-разному. os.system() просто отправляет строку в shell, а subprocess даёт полный контроль: можно передавать параметры, получать вывод, обрабатывать ошибки, работать с потоками ввода/вывода и даже запускать пайплайны, как в bash.

Как быстро и просто всё настроить?

Всё, что нужно — это Python (желательно свежий, хотя бы 3.6+), и стандартная библиотека. Оба модуля идут “из коробки”, ничего ставить не надо.

  • Для os — импортируете модуль и вызываете os.system() или os.popen().
  • Для subprocess — импортируете модуль и используете subprocess.run(), subprocess.Popen() и другие методы.

Вот минимальный пример для запуска команды ls -la:


import os
os.system('ls -la')

А вот современный способ:


import subprocess
subprocess.run(['ls', '-la'])

Всё, вы уже можете запускать команды. Но дьявол, как всегда, в деталях.

Примеры, схемы, практические советы

Сравнение: os vs subprocess

Критерий os.system() subprocess.run()
Простота Очень просто, но мало контроля Чуть сложнее, но гибко
Безопасность Уязвим к инъекциям, особенно с переменными Безопаснее, параметры передаются списком
Получение вывода Только через os.popen() или перенаправление Легко получить stdout/stderr
Работа с пайпами Плохо Отлично
Обработка ошибок Только по коду возврата Исключения, коды, stderr
Кроссплатформенность Зависит от shell Лучше, но всё равно зависит от команд

Положительный кейс: резервное копирование

Нужно сделать бэкап базы данных и отправить его на удалённый сервер. Вот как это можно сделать с помощью subprocess:


import subprocess
import datetime

backup_file = f"/tmp/backup_{datetime.date.today()}.sql"
cmd = ["mysqldump", "-u", "root", "-pYOURPASS", "mydb"]
with open(backup_file, "w") as f:
  subprocess.run(cmd, stdout=f, check=True)

# Отправляем на сервер
subprocess.run(["scp", backup_file, "user@remote:/backups/"], check=True)

Плюсы: полный контроль, можно обрабатывать ошибки, логировать, отправлять уведомления.

Отрицательный кейс: уязвимость через os.system()

Ваша программа принимает имя файла от пользователя и удаляет его:


import os
filename = input("Введите имя файла для удаления: ")
os.system(f"rm {filename}")

Если пользователь введёт file.txt; rm -rf /, вы потеряете всё. Никогда так не делайте! Используйте subprocess и передавайте параметры списком:


import subprocess
filename = input("Введите имя файла для удаления: ")
subprocess.run(["rm", filename], check=True)

Практические советы

  • Всегда используйте subprocess, если нужна безопасность и контроль.
  • Передавайте параметры как список, а не строкой.
  • Используйте check=True, чтобы ловить ошибки через исключения.
  • Для сложных пайплайнов используйте subprocess.Popen() и связывайте процессы через stdin/stdout.
  • Не забывайте про timeout — зависшие процессы могут “повесить” ваш скрипт.
  • Для получения вывода используйте capture_output=True или stdout=subprocess.PIPE.

Полный список команд и примеров

Вот подборка часто используемых паттернов:


# Запуск команды и ожидание завершения
subprocess.run(["ls", "-la"], check=True)

# Получение вывода
result = subprocess.run(["df", "-h"], capture_output=True, text=True)
print(result.stdout)

# Запуск команды с пайпом
p1 = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "nginx"], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
output = p2.communicate()[0]
print(output.decode())

# Запуск команды с таймаутом
try:
  subprocess.run(["sleep", "10"], timeout=5)
except subprocess.TimeoutExpired:
  print("Процесс превысил лимит времени!")

# Проверка кода возврата
result = subprocess.run(["ls", "/nonexistent"], capture_output=True)
if result.returncode != 0:
  print("Ошибка:", result.stderr.decode())

Похожие решения, программы и утилиты

  • shlex — разбивает строки команд на аргументы (удобно для парсинга).
  • sh — сторонняя библиотека, позволяет писать shell-команды как Python-функции.
  • plumbum — мощная библиотека для shell-скриптинга на Python.
  • pexpect — для автоматизации интерактивных команд (например, ssh, ftp).

Статистика и сравнение с другими решениями

  • Модуль subprocess используется в 90% современных Python-проектов, связанных с автоматизацией серверов (по данным GitHub).
  • Библиотека sh удобна для простых задач, но не входит в стандартную библиотеку и требует установки.
  • Встроенные средства bash-скриптов быстрее для простых задач, но Python выигрывает в читаемости, масштабируемости и интеграции с другими библиотеками.

Интересные факты и нестандартные способы использования

  • Можно запускать не только shell-команды, но и любые исполняемые файлы, даже если это не bash, а, например, скрипты на Perl, Ruby, Go и т.д.
  • С помощью subprocess можно реализовать свой мини-оркестратор процессов, например, для параллельного запуска задач.
  • Можно использовать subprocess для тестирования shell-скриптов прямо из Python — удобно для CI/CD.
  • В связке с asyncio можно запускать процессы асинхронно, не блокируя основной поток.

Какие новые возможности открываются?

  • Автоматизация рутинных задач: резервное копирование, деплой, мониторинг, обновления.
  • Интеграция с внешними сервисами и утилитами (например, запускать curl или rsync из Python).
  • Создание своих CLI-утилит с расширенной логикой и обработкой ошибок.
  • Организация пайплайнов обработки данных, как в bash, но с возможностями Python.
  • Безопасное выполнение команд с контролем доступа и логированием.

Вывод — заключение и рекомендации

Вызов системных команд из Python — это не просто “фича”, а мощный инструмент для автоматизации и интеграции. Если вы работаете с серверами, пишете скрипты для обслуживания, мониторинга или деплоя, используйте subprocess — это современно, безопасно и гибко. os.system() оставьте для простых, одноразовых задач или для совместимости со старым кодом, но не используйте его в новых проектах.

Рекомендации:

  • Для новых проектов — только subprocess.
  • Передавайте параметры как список, не используйте shell=True без необходимости.
  • Обрабатывайте ошибки, используйте check=True и ловите исключения.
  • Для сложных пайплайнов — Popen и пайпы.
  • Для интерактивных задач — посмотрите в сторону pexpect.

Если вы хотите попробовать всё это на практике — закажите VPS или выделенный сервер и начните автоматизировать свои задачи уже сегодня. Python + subprocess — это ваш швейцарский нож для серверной автоматизации!

Официальная документация:


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

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

Leave a reply

Your email address will not be published. Required fields are marked