


Для обычного запуска внешней команды из Python начните с subprocess.run: передайте аргументы списком, задайте тайм-аут и явно решите, считать ли ненулевой код завершения ошибкой. В практикуме Mentoring.digital используем дочерний Python, поэтому пример не зависит от наличия сторонней утилиты.
capture_output=True собирает оба потока, а text=True возвращает строки. Кодировку выбирайте по договорённости с запускаемой программой. В примере вывод состоит из ASCII-символов и явно указан UTF-8.
import subprocess
import sys
command = [
sys.executable, "-c",
"import sys; print('ready'); print('notice', file=sys.stderr)",
]
try:
result = subprocess.run(
command, capture_output=True,
text=True, encoding="utf-8",
check=True, timeout=3,
)
except subprocess.CalledProcessError as exc:
print("exit:", exc.returncode)
print("stderr:", exc.stderr)
except subprocess.TimeoutExpired:
print("child process exceeded the time limit")
else:
print(result.stdout.strip()) # ready
print(result.stderr.strip()) # notice
Сообщение в stderr само по себе не означает неудачу. Некоторые программы пишут туда предупреждения при успешном коде завершения. Решение в этом примере основано на returncode, а содержимое потока помогает понять причину.
При check=True ненулевой код вызывает CalledProcessError. В исключении доступны код и перехваченные потоки. Без check тот же запуск вернёт результат, и код нужно проверить самостоятельно.
При превышении timeout функция run завершает дочерний процесс, дожидается его и поднимает TimeoutExpired. Создание процесса на некоторых платформах нельзя прервать этим таймером. Поэтому параметр не является строгой гарантией общего времени вызова. Ошибка запуска, например отсутствие исполняемого файла, относится к OSError и требует отдельной обработки в рабочем приложении.
По умолчанию shell=False. Передавайте исполняемый файл и каждый аргумент отдельным элементом списка. Не склеивайте пользовательский ввод с командной строкой и не включайте shell=True только ради привычного синтаксиса терминала.
Перехваченный вывод хранится в памяти. Для большого или непрерывного потока выберите чтение по мере поступления либо перенаправление в файл. run с capture_output удобен для ограниченного результата, например ответа небольшой служебной команды.
Сначала выполните пример. Затем замените код дочернего процесса на import sys; sys.exit(2), а потом на import time; time.sleep(5). Проверьте, какая ветка срабатывает в каждом случае. Не используйте для упражнения рабочие утилиты, изменяющие файлы или данные.
Такие задачи входят в практику обучения Python. Обработку ошибок конкретной утилиты можно разобрать с ментором по Python.