Управление системными командами в скриптах Python
Выполнение команд в Python: обзор возможностей
Python предоставляет несколько способов выполнения системных команд. Выбор зависит от задачи: нужно ли получить вывод, обработать ошибки, выполнить сложную цепочку команд. Рассмотрим наиболее популярные подходы.
Основное решение: subprocess.run
Модуль subprocess является современным и предпочтительным способом запуска дочерних процессов. Функция subprocess.run позволяет выполнить команду, дождаться её завершения и получить объект с результатами.
import subprocess
result = subprocess.run(['ls', '-la'], capture_output=True, text=True)
print('stdout:', result.stdout)
print('stderr:', result.stderr)
print('return code:', result.returncode)Python os environ (переменные окружения os.environ в python)
Пояснение: передача команды в виде списка аргументов (без shell=True) повышает безопасность. Параметр capture_output захватывает stdout и stderr, text=True возвращает строки вместо байтов.
Типичные ошибки:
- Забыли указать полный путь к программе или программа не в PATH.
- При использовании shell=True и неправильном экранировании возможны проблемы безопасности.
- Необработанные нестандартные коды завершения.
Как выполнить команду и забыть о результате?
Для простого запуска без захвата вывода подходит os.system.
import os
os.system('echo Hello')Python os getenv (получение переменной окружения os.getenv в python)
Проблемы: код возврата теряется, вывод не сохраняется, подвержен инъекциям.
Как получить вывод команды построчно?
Можно использовать subprocess.Popen с pipe.
import subprocess
proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
out, _ = proc.communicate(input='строка для передачи')
print(out)
Python os listdir (список файлов в директории os.listdir в python)
Этот способ даёт больше контроля, но требует ручного управления потоками.
Как выполнить команду с тайм-аутом?
У subprocess.run есть параметр timeout.
try:
result = subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired:
print('Процесс превысил время')При срабатывании тайм-аута процесс завершается.
Расширенные примеры выполнения команд
1. Работа с окружением и текущим каталогом
import subprocess
import os
# Запуск с изменённым окружением
env = os.environ.copy()
env['MY_VAR'] = 'value'
result = subprocess.run(['env'], env=env, capture_output=True, text=True)
print(result.stdout)... MY_VAR=value ...
2. Передача данных через stdin и получение результата
proc = subprocess.Popen(['grep', 'error'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
out, err = proc.communicate(input='line1\nline with error\nline3')
print('matched:', out)matched: line with error
3. Асинхронное выполнение команды
import asyncio
async def run_cmd():
proc = await asyncio.create_subprocess_exec(
'ls', '-la',
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await proc.communicate()
print(stdout.decode())
asyncio.run(run_cmd())4. Запуск цепочки команд с конвейером
# Эмуляция ls | grep py
p1 = subprocess.Popen(['ls'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['grep', 'py'], stdin=p1.stdout, stdout=subprocess.PIPE)
p1.stdout.close()
output = p2.communicate()[0]
print(output.decode())example.py script.py
5. Безопасное выполнение команды с shell=True с помощью shlex
import shlex
import subprocess
cmd = 'echo "Hello $USER"'
args = shlex.split(cmd)
result = subprocess.run(args, capture_output=True, text=True)
print(result.stdout)Hello $USER