Запуск исполняемых файлов и открытие документов средствами Python

Раздел: ОС -> Управление процессами

Запуск файлов и программ из Python: subprocess и os.startfile

Основное эффективное решение: subprocess.run

Модуль subprocess (начиная с Python 3.5) предоставляет унифицированный интерфейс для запуска внешних процессов. Функция run() блокирует выполнение до завершения запущенной программы, возвращает объект CompletedProcess, позволяющий проверить код возврата и при необходимости получить вывод.


import subprocess

# Запуск утилиты с аргументами
result = subprocess.run(['ls', '-la'], capture_output=True, text=True, encoding='utf-8')
print(result.stdout)
  

Python launch file (запуск файла (программы) из python (subprocess, os.startfile))

Пояснение: список строк ['ls', '-la'] – команда и её аргументы. Параметр capture_output=True забирает stdout и stderr; text=True возвращает строки, а не байты. После завершения проверяется result.returncode – 0 означает успех.

Возникающие проблемы

  • Ошибка FileNotFoundError – если программа не найдена. Решение: указывать полный путь или убедиться, что она в PATH.
  • Ошибка subprocess.CalledProcessError – когда check=True и код возврата не ноль. Можно обработать через try/except.
  • Проблемы с кодировкой вывода – использовать encoding или обрабатывать байты.

Как открыть файл в программе по умолчанию, не запуская новую консоль?

Использовать os.startfile() (только Windows). Эта функция открывает файл или папку так же, как двойной клик мыши.


import os
os.startfile('document.pdf')
  

На Linux и macOS применяется subprocess.run(['xdg-open', 'document.pdf']) или open.

Возможные ошибки

  • Файл не найден – FileNotFoundError. Проверить существование через os.path.exists.
  • Отсутствие ассоциации – на Windows вызывает исключение OSError с кодом 1155. Можно использовать subprocess с командой start.

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

Класс subprocess.Popen создаёт дочерний процесс в фоновом режиме. Вызов Popen.communicate() ждёт завершения, но если этого не делать – код продолжает выполняться параллельно.


import subprocess

process = subprocess.Popen(['sleep', '10'])  # процесс зависнет на 10 секунд
print('Процесс запущен, PID:', process.pid)
# Можно продолжить работу
  

Если не вызвать process.wait() или process.communicate(), процесс останется «сиротой» после завершения Python. Может забить ресурсы. Рекомендуется сохранять объект и завершить явно (process.terminate()) или дождаться.

Как запустить команду с использованием оболочки (shell) и подстановками?

Параметр shell=True передаёт строку в системную оболочку. Подходит для сложных команд с пайпами или переменными среды.


subprocess.run('echo $HOME | wc -c', shell=True, capture_output=True, text=True)
  

Опасности

  • Инъекции команд, если строка содержит пользовательский ввод. Никогда не использовать с непроверенными данными.
  • Различия оболочек (sh, bash, cmd). Код может быть непереносим.

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

Передайте stdout=subprocess.PIPE и stderr=subprocess.PIPE при использовании Popen, затем communicate() вернёт кортеж (stdout, stderr).


import subprocess
p = subprocess.Popen(['ls', '/nonexistent'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
print('STDOUT:', out.decode())
print('STDERR:', err.decode())
  

Как запустить программу с ограничением по времени?

Используйте timeout параметр в subprocess.run() (Python 3.6+). При превышении лимита выбрасывается subprocess.TimeoutExpired.


import subprocess
try:
    subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired:
    print('Процесс превысил время ожидания и был убит')
  

На старых версиях Python можно реализовать таймаут через Popen и process.wait(timeout=...).

Расширенные примеры и нестандартные сценарии

Пример

import subprocess, os, sys

# 1. Запуск с передачей данных через stdin и получением вывода
p = subprocess.Popen(['sort'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
out, _ = p.communicate(input='banana\napple\ncherry\n')
print('Отсортированные фрукты:')
print(out)
# Результат: apple banana cherry
Отсортированные фрукты:
apple
banana
cherry
Пример

# 2. Запуск с изменением рабочей директории
result = subprocess.run(['pwd'], cwd='/tmp', capture_output=True, text=True)
print('Текущая папка:', result.stdout.strip())
# Результат: /tmp
Пример

# 3. Использование os.startfile для открытия URL в браузере (только Windows)
import os
os.startfile('https://python.org')  # откроется в браузере по умолчанию
Пример

# 4. Запуск консольного приложения с постоянным потоком вывода (live output)
process = subprocess.Popen(['ping', '127.0.0.1', '-c', '5'], stdout=subprocess.PIPE, text=True)
for line in process.stdout:
    print('PING:', line.strip())
process.wait()
PING: PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
PING: 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.017 ms
...
Пример

# 5. Запуск с пользовательским окружением (env)
my_env = os.environ.copy()
my_env['MY_VAR'] = '42'
subprocess.run(['echo', '$MY_VAR'], shell=True, env=my_env, capture_output=True, text=True)
Пример

# 6. Обработка пути с пробелами (используйте список, а не строку!)
program = r'C:\Program Files\MyApp\app.exe'
subprocess.run([program, '--arg1', 'value with space'])
Пример

# 7. Получение кода возврата и вывод при ошибке
try:
    subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as e:
    print(f'Команда завершилась с кодом {e.returncode}')

Запуск файла (программы) из Python (subprocess, os.startfile) - comments

En
Python launch file (python)