Python

Как завершить подпроцесс Python, запущенный с shell = True

Я запускаю подпроцесс следующей командой:

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

 

Однако, когда я пытаюсь его завершить, используя:

p.terminate()

или же:

p.kill()

 

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

Обратите внимание, что, когда я запускаю команду с:

p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)

 

он действительно завершается успешно при вызове p.terminate().

 

Ответ 1

Используйте группу процессов, чтобы разрешить отправку сигнала всем процессам в группах. Для этого вы должны прикрепить идентификатор сеанса к родительскому процессу порожденных/дочерних процессов, который в вашем случае является оболочкой. Это сделает его лидером группы процессов. Итак, теперь, когда сигнал отправляется лидеру группы процессов, он передается всем дочерним процессам этой группы.

Вот код:

import os

import signal

import subprocess

# Команда os.setsid() передается в аргументе preexec_fn, поэтому.

# она выполняется после fork() и перед exec() для запуска оболочки.

pro = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, preexec_fn=os.setsid) 

os.killpg(os.getpgid(pro.pid), signal.SIGTERM)  # Отправляет сигнал всем группам процессов

 

Ответ 2

p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)

p.kill()

 

p.kill() заканчивает выполнение и завершает процесс оболочки, но cmd все еще работает.

Я нашел удобное решение:

p = subprocess.Popen("exec " + cmd, stdout=subprocess.PIPE, shell=True)

 

Это заставит cmd унаследовать процесс оболочки вместо того, чтобы оболочка запускала дочерний процесс, который не завершается. p.pid тогда будет идентификатором вашего процесса cmd, и p.kill() должен сработать.

 

Ответ 3

Если вы можете использовать psutil, это отлично работает:

import subprocess

import psutil

 

def kill(proc_pid):

    process = psutil.Process(proc_pid)

    for proc in process.children(recursive=True):

        proc.kill()

    process.kill()

 

proc = subprocess.Popen(["infinite_app", "param"], shell=True)

try:

    proc.wait(timeout=3)

except subprocess.TimeoutExpired:

    kill(proc.pid)

 

Ответ 4

Я мог бы сделать это, используя:

from subprocess import Popen

process = Popen(command, shell=True)

Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))

 

Это завершает cmd.exe программу, для которой дается эта команда (в Windows).

 

Ответ 5

Ни один из ответов у меня не сработал, поэтому я даю код, который действительно работает. В моем случае даже после завершения процесса .kill() и получения .poll() кода возврата, процесс не завершился.

Следуя subprocess.Popen из документации:

«... для правильной очистки приложение с допустимым поведением должно завершить дочерний процесс и завершить обмен данными ...»

proc = subprocess.Popen(...)

 

try:

    outs, errs = proc.communicate(timeout=15)

except TimeoutExpired:

    proc.kill()

    outs, errs = proc.communicate()

 

В моем случае мне не хватало proc.communicate() после вызова proc.kill(). Это очищает процесс stdin, stdout ... и завершает процесс. 

Схожие статьи

Библиотека Json Python: как научиться пользоваться ей самостоятельно?
Python

Библиотека Json Python: как научиться пользоваться ей самостоятельно?

Python

Как сделать скриншот с помощью скрипта Python в Linux

Выход из цикла в С и Python: как правильно останавливать
Python

Выход из цикла в С и Python: как правильно останавливать

Игровой движок на Python: тестовая, консольная игра
Python

Игровой движок на Python: тестовая, консольная игра