Вопрос-Ответ

How to terminate a python subprocess launched with shell=True

Как завершить подпроцесс 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

# The os.setsid() is passed in the argument preexec_fn so
# it's run after the fork() and before exec() to run the shell.
pro = subprocess.Popen(cmd, stdout=subprocess.PIPE,
shell=True, preexec_fn=os.setsid)

os.killpg(os.getpgid(pro.pid), signal.SIGTERM) # Send the signal to all the process groups
Ответ 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)

python linux subprocess