- Home »

Вызов системных команд в 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 — это ваш швейцарский нож для серверной автоматизации!
Официальная документация:
В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.
Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.