Запуск исполняемых файлов (exe) средствами Python
Основные способы запуска EXE из Python
Как надежно запустить exe-файл и дождаться его завершения?
Рекомендуемый способ - модуль subprocess, а именно функция run(). Она позволяет выполнить внешнюю программу, дождаться окончания и получить информацию о результате.
import subprocess
result = subprocess.run(['C:\\Program Files\\MyApp\\app.exe', '--arg1', 'value1'],
capture_output=True, text=True, encoding='utf-8')
print('Код возврата:', result.returncode)
print('stdout:', result.stdout)
print('stderr:', result.stderr)Python run exe file (запуск exe-файла из python)
Объяснение шагов:
- Передаётся список, где первый элемент - путь к exe, остальные - аргументы.
- capture_output=True - захват stdout и stderr.
- text=True - вывод в виде строки, а не байтов.
- encoding='utf-8' - кодировка для корректного чтения русского текста.
- Результат хранится в объекте CompletedProcess.
Типичные ошибки:
- FileNotFoundError - если путь указан неверно. Решение: проверить существование файла через os.path.exists() или использовать абсолютный путь.
- UnicodeDecodeError - при несовпадении кодировки. Решение: явно указать кодировку (например, 'cp866' для русского вывода в консоли Windows).
- Программа запускается, но не завершается. Решение: установить timeout в run().
Как выполнить команду через командную строку?
Функция os.system() из стандартного модуля os запускает команду в оболочке ОС. Просто, но нет контроля над выводом.
import os
exit_code = os.system('notepad.exe')
print('Код завершения:', exit_code)Python send files (отправка файлов в python)
Проблемы: нельзя захватить stdout/stderr, код возврата ограничен (только 0 или 1 на некоторых системах), уязвимость к инъекции команд при использовании строк с пользовательским вводом.
Как открыть файл или программу, как при двойном клике?
os.startfile() (Windows) имитирует двойной щелчок по файлу. Открывает exe без ожидания завершения.
import os
os.startfile('C:\\Windows\\System32\\calc.exe')
Python system path (системные вызовы и файловая система в python)
Недостатки: нет возможности передать аргументы или дождаться завершения. Работает только в Windows.
Как запустить программу асинхронно, не дожидаясь её завершения?
subprocess.Popen() даёт полный контроль: запуск в фоне, обмен данными через пайпы.
import subprocess
proc = subprocess.Popen(['ping', '8.8.8.8'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# Можно делать другую работу
stdout, stderr = proc.communicate(timeout=10)
print('Вывод:', stdout.decode('cp866'))Python py file system (работа с файловой системой в python (os, shutil))
- Зависание при большом выводе без communicate() - решение: читать данные потоково или использовать subprocess.PIPE.
- Необходимость ручного закрытия пайпов.
Как использовать WinAPI для запуска процесса?
Модуль ctypes позволяет вызывать функции Windows API, такие как CreateProcess.
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.CreateProcessW(None, 'notepad.exe', None, None, False, 0, None, None, None, None)аргументы программы python (аргументы командной строки программы на python)
Сложная работа с типами, риск падения интерпретатора при ошибках. Требуется глубокое знание WinAPI.
Как запустить exe с правами администратора или используя ShellExecute?
Библиотека pywin32 (win32api, win32com) предоставляет ShellExecute для запуска с указанием операции (например, 'runas').
import win32api
win32api.ShellExecute(0, 'runas', 'setup.exe', None, None, 1)Требуется установка pywin32 (pip install pywin32). Непереносимость на Linux/macOS.
Расширенные примеры запуска exe из Python
Ниже приведены более сложные сценарии, демонстрирующие гибкость модуля subprocess и других подходов.
Пример 1: Запуск с таймаутом и обработкой ошибок
import subprocess
try:
result = subprocess.run(['timeout', '5'], timeout=3, capture_output=True, text=True)
print('Команда завершена с кодом:', result.returncode)
except subprocess.TimeoutExpired:
print('Процесс превысил время ожидания')Процесс превысил время ожидания
Пример 2: Перенаправление вывода в файл
import subprocess
with open('output.log', 'w') as f:
subprocess.run(['dir', '/B'], stdout=f, encoding='cp866', shell=True)Параметр shell=True позволяет использовать команды оболочки (например, dir).
Пример 3: Запуск скрытого окна (Windows)
import subprocess
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si.wShowWindow = subprocess.SW_HIDE
proc = subprocess.Popen(['notepad.exe'], startupinfo=si)
proc.wait()Пример 4: Передача переменных окружения
import subprocess, os
my_env = os.environ.copy()
my_env['MY_VAR'] = 'значение'
subprocess.run(['python', '-c', 'import os; print(os.environ["MY_VAR"])'], env=my_env)значение
Пример 5: Запуск от имени другого пользователя (Windows)
import win32api
# 'runas' открывает диалог UAC или требует пароль
win32api.ShellExecute(0, 'runas', 'cmd.exe', '/k whoami', None, 1)Пример 6: Асинхронный запуск с потоковым чтением вывода
import subprocess, threading
def read_output(stream, label):
for line in stream:
print(f'[{label}] {line.decode("cp866").strip()}')
proc = subprocess.Popen(['ping', '8.8.8.8', '-t'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
thread_out = threading.Thread(target=read_output, args=(proc.stdout, 'OUT'))
thread_err = threading.Thread(target=read_output, args=(proc.stderr, 'ERR'))
thread_out.start()
thread_err.start()
import time
time.sleep(3)
proc.terminate()Результат (сокращён):
[OUT] Ответ от 8.8.8.8: число байт=32 время=45мс TTL=117 [OUT] Ответ от 8.8.8.8: число байт=32 время=44мс TTL=117
Пример 7: Запуск PowerShell скрипта внутри Python
import subprocess
ps_cmd = 'Get-Process | Where-Object {$_.ProcessName -eq "notepad"} | Format-Table Name, Id'
result = subprocess.run(['powershell', '-Command', ps_cmd], capture_output=True, text=True)
print(result.stdout)Name Id ---- -- notepad 1234
Пример 8: Использование ctypes для получения PID созданного процесса
import ctypes
kernel32 = ctypes.windll.kernel32
class PROCESS_INFORMATION(ctypes.Structure):
_fields_ = [('hProcess', ctypes.c_void_p),
('hThread', ctypes.c_void_p),
('dwProcessId', ctypes.c_ulong),
('dwThreadId', ctypes.c_ulong)]
class STARTUPINFO(ctypes.Structure):
_fields_ = [('cb', ctypes.c_ulong),
('lpReserved', ctypes.c_wchar_p),
('lpDesktop', ctypes.c_wchar_p),
('lpTitle', ctypes.c_wchar_p),
('dwX', ctypes.c_ulong),
('dwY', ctypes.c_ulong),
('dwXSize', ctypes.c_ulong),
('dwYSize', ctypes.c_ulong),
('dwXCountChars', ctypes.c_ulong),
('dwYCountChars', ctypes.c_ulong),
('dwFillAttribute', ctypes.c_ulong),
('dwFlags', ctypes.c_ulong),
('wShowWindow', ctypes.c_ushort),
('cbReserved2', ctypes.c_ushort),
('lpReserved2', ctypes.c_byte * 0),
('hStdInput', ctypes.c_void_p),
('hStdOutput', ctypes.c_void_p),
('hStdError', ctypes.c_void_p)]
si = STARTUPINFO()
si.cb = ctypes.sizeof(si)
pi = PROCESS_INFORMATION()
kernel32.CreateProcessW(None, 'calc.exe', None, None, False, 0, None, None, ctypes.byref(si), ctypes.byref(pi))
print('PID процесса:', pi.dwProcessId)
kernel32.CloseHandle(pi.hProcess)
kernel32.CloseHandle(pi.hThread)PID процесса: 23456