Завершение подпроцесса Python с shell=True: советы и лайфхаки

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы с немедленным эффектом остановить подпроцесс, созданный с параметром shell=True, вам следует применить Popen из модуля subprocess, а затем вызвать метод terminate():

Python
Скопировать код
import subprocess

# Создаем подпроцесс
proc = subprocess.Popen('ваша_команда', shell=True)

# Завершаем его
proc.terminate()

Это приведет к отправке сигнала SIGTERM. Если процесс не откликается на эту команду, используйте proc.kill() для отправки сигнала SIGKILL.

Кинга Идем в IT: пошаговый план для смены профессии

Групповая терапия: управление группами процессов

Если ваш подпроцесс запустил семейство дочерних процессов, их недостаточно просто остановить. В таком случае необходимо использовать os.setsid() в параметре preexec_fn метода Popen для создания отдельной группы:

Python
Скопировать код
import os
import subprocess
import signal

# Запускаем подпроцесс в отдельной группе
proc = subprocess.Popen('ваша_команда', shell=True, preexec_fn=os.setsid)

# Завершаем всю группу процессов
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)

Уклонение и защита: как избегать использования shell=True

В использовании shell=True можно отказаться, если выполнять команды напрямую, передавая их в виде списка методу Popen:

Python
Скопировать код
import subprocess

# Команда передается в виде списка аргументов
cmd = ['ваша_команда', 'арг1', 'арг2']

# Выполняем команду без оболочки
proc = subprocess.Popen(cmd, shell=False)

# Останавливаем подпроцесс
proc.terminate()

Вы можете использовать cmd.split() для простой конвертации строки в список.

Как справиться с неподдающимися процессами

Если процесс не реагирует на сигнал SIGTERM, обратитесь к библиотеке psutil для его посредственного завершения:

Python
Скопировать код
import psutil

# Обертываем процесс в psutil
process = psutil.Process(proc.pid)
for child in process.children(recursive=True):
    child.kill()  # Принудительно завершаем все дочерние процессы
process.kill()  # Завершаем главный процесс

Управление в ситуации кризиса: обработка истечения времени

Если подпроцесс должен завершиться в определенное время, используйте TimeoutExpired:

Python
Скопировать код
try:
    proc.wait(timeout=3)  # Даем процессу 3 секунды для завершения
except subprocess.TimeoutExpired:
    proc.kill()  # Принудительно останавливаем процесс

Если вы используете Windows...

Windows-пользователи для прекращения работы процессов должны использовать команду taskkill:

Python
Скопировать код
import subprocess

pid = proc.pid
subprocess.run(f"TASKKILL /F /PID {pid} /T", shell=True)

Визуализация

Представьте подпроцесс в виде бумажного фонаря, которым вы должны аккуратно управлять:

Запуск: 🏮🆙 (подпроцесс начинает работу)
Завершение: 🏮👇 (подпроцесс останавливается и прекращает работу)

Используйте модуль subprocess и метод terminate() для управления подпроцессами:

Python
Скопировать код
import subprocess

# Запускаем наш бумажный фонарь 🏮🆙
proc = subprocess.Popen('ваша_команда', shell=True)

# ... любуемся его полетом ...

# Призываем его возвратиться домой 🏮👇
proc.terminate()

В случае серьезной задачи: методы завершения subprocess

Секретное оружие: префикс exec

Если нужно использовать shell=True, вы можете добавить префикс exec в команду, чтобы быть уверенным, что kill() действительно завершит процесс:

Python
Скопировать код
proc = subprocess.Popen('exec ваша_команда', shell=True)

Высокая прецизность с помощью psutil

Библиотека psutil позволяет точно и эффективно управлять процессами:

Python
Скопировать код
import psutil

psutil.Process(proc.pid).kill()  # Завершаем процесс

При работе с каналами

Когда вы работаете с exec, помните о его влиянии на перенаправление и трубопроводы — старайтесь строить команды аккуратно.

Полезные ресурсы

  1. Официальная документация Python по модулю subprocess
  2. Вопрос на Stack Overflow: Как завершить подпроцесс в Python
  3. Официальная документация Python по обработке сигналов
  4. Информация о os.kill
  5. Документация к библиотеке psutil
  6. Руководство по обработке сигналов в Python
  7. Обсуждение на Stack Overflow: Управление процессами в Windows с помощью подпроцессов