Способы выполнения сторонних приложений из скрипта на Python

Раздел: Основы Python -> Выполнение программ

Запуск программ из Python: обзор методов

Для вызова внешних исполняемых файлов или системных команд Python предоставляет несколько инструментов. Наиболее современным и гибким считается модуль subprocess. В этом разделе рассмотрены разные подходы, начиная от простых и заканчивая продвинутыми.

Основной рекомендуемый способ - функция subprocess.run(). Она объединяет в себе возможности многих старых функций и добавляет безопасность при работе с аргументами.

Пример базового запуска:

import subprocess
result = subprocess.run(['python', '--version'], capture_output=True, text=True)
print(result.returncode)
print(result.stdout)

Python run cmd (запуск python скриптов через cmd)

0
Python 3.12.0

запустить программу через python (запуск программы через python)

Аргумент capture_output=True перенаправляет stdout и stderr в объект результата. text=True декодирует вывод в строку (иначе возвращаются байты). Код возврата доступен как result.returncode.

Типичные ошибки:

  • Неверный путь к исполняемому файлу - вызывается FileNotFoundError.
  • Забыли text=True - вывод в байтах, что усложняет обработку.
  • Использование shell=True с непроверенными входными данными - риск инъекции команд.

Решение: всегда передавать аргументы в виде списка, явно указывать text=True, избегать shell=True если это не критично.

Для проверки успешности выполнения используйте параметр check=True. Тогда при ненулевом коде возврата будет выброшено исключение CalledProcessError.

result = subprocess.run(['false'], check=True, capture_output=True, text=True)
subprocess.CalledProcessError: Command '['false']' returned non-zero exit status 1.

Передача данных на стандартный ввод:

result = subprocess.run(['grep', 'Python'], input='Python - язык программирования', capture_output=True, text=True)
print(result.stdout)
Python - язык программирования

Как выполнить команду и получить только код возврата?

Функция os.system() из модуля os - самый простой способ, но она возвращает только код возврата и не позволяет захватить вывод.

import os
code = os.system('python --version')
print(code)
0

Проблема: вывод команды попадает в консоль скрипта, его невозможно обработать программно. Кроме того, os.system() использует оболочку, что несет риски безопасности.

Как захватить стандартный вывод программы в python2 стиле?

Функция os.popen() позволяет читать вывод, но использование устарело в пользу subprocess.

output = os.popen('echo Привет').read()
print(output)
Привет

Недостатки: нет управления stderr, нет возможности передать данные на ввод, сложная обработка ошибок.

Как запустить команду и дождаться завершения с кодом?

Функция subprocess.call() (устаревшая) аналогична subprocess.run() без захвата вывода.

code = subprocess.call(['ls', '-l'])

Она не возвращает захваченный вывод, только код. Теперь предпочтительнее использовать subprocess.run().

Как получить вывод команды и проверить успешность?

Функция subprocess.check_output() возвращает вывод, но при ошибке выбрасывает исключение.

out = subprocess.check_output(['python', '-c', 'print("hello")'])
print(out.decode())  # нужно декодировать
hello

Вывод в байтах, нет доступа к коду возврата отдельно, неудобна передача stdin.

Как запустить программу с полным контролем stdin/stdout/stderr?

Класс subprocess.Popen даёт максимальную гибкость. Подходит для интерактивных программ или длительных процессов.

proc = subprocess.Popen(['python', '-c', 'import sys; sys.stdout.write("in")'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
out, err = proc.communicate(input='data')
print(out)
in

Если не вызвать communicate(), программа может зависнуть из-за заполненного буфера. Всегда закрывайте каналы или используйте communicate().

Расширенные примеры запуска программ

Запуск с переменными окружения

Пример
import subprocess, os
env = os.environ.copy()
env['MY_VAR'] = 'value'
result = subprocess.run(['env'], capture_output=True, text=True, env=env)
print('MY_VAR' in result.stdout)
True

Используется копия текущего окружения, чтобы не изменить его в родительском процессе.

Параллельный запуск нескольких команд

Пример
import subprocess
processes = []
for i in range(3):
    p = subprocess.Popen(['python', '-c', f'print({i})'])
    processes.append(p)
for p in processes:
    p.wait()
print('Готово')
0
1
2
Готово

Каждый процесс работает независимо. После завершения всех - программа продолжает выполнение.

Чтение вывода в реальном времени

Пример
proc = subprocess.Popen(['python', '-u', '-c', 'import time; [print(i) or time.sleep(0.5) for i in range(5)]'], stdout=subprocess.PIPE, text=True)
for line in iter(proc.stdout.readline, ''):
    print(line.strip())
proc.wait()
0
1
2
3
4

Флаг -u отключает буферизацию вывода Python. iter() используется для построчного чтения до конца потока.

Передача сложных данных через stdin (байты)

Пример
proc = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, _ = proc.communicate(input=b'binary data \x00 test')
print(out)
b'binary data \x00 test'

Если данные содержат нулевые байты, используйте байтовый режим (text=False по умолчанию).

Ограничение времени выполнения (timeout)

Пример
try:
    result = subprocess.run(['sleep', '10'], timeout=5, capture_output=True)
except subprocess.TimeoutExpired:
    print('Процесс превысил время')
Процесс превысил время

При срабатывании таймера процесс убивается по SIGKILL (на Unix). Для мягкого завершения используйте Popen и preexec_fn.

Запуск GUI-приложений и игнорирование вывода

Пример
subprocess.Popen(['notepad.exe'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

На Windows откроется блокнот. Вывод направляется в никуда, чтобы не блокировать консоль.

Асинхронный запуск с asyncio

Пример
import asyncio

async def run_cmd():
    proc = await asyncio.create_subprocess_exec(
        'python', '-c', 'print("Async")',
        stdout=asyncio.subprocess.PIPE)
    out, _ = await proc.communicate()
    print(out.decode())

asyncio.run(run_cmd())
Async

Используется asyncio.create_subprocess_exec для неблокирующего выполнения команд в асинхронном коде.

Запуск программы через Python - comments

En
запустить программу через python (python)