Jak zakończyć podproces Pythona uruchomiony z shell = True

Uruchamiam podproces za pomocą następującego polecenia:

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

Jednak gdy próbuję zabić używając:

p.terminate()

Lub

p.kill()

Polecenie działa w tle, więc zastanawiałem się, jak Mogę zakończyć proces.

Zauważ, że gdy uruchamiam komendę z:

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

Kończy się pomyślnie podczas wydawania p.terminate().

Author: Piotr Dobrogost, 2011-01-25

7 answers

Użyj grupy procesów , aby umożliwić wysłanie sygnału do wszystkich procesów w grupach. W tym celu należy dołączyć identyfikator sesji do procesu macierzystego procesów potomnych, który w Twoim przypadku jest powłoką. To uczyni go liderem grupy procesów. Więc teraz, kiedy sygnał jest wysyłany do lidera grupy procesów, jest on przesyłany do wszystkich procesów potomnych tej grupy.

Oto kod:

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
 321
Author: mouad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-05 18:02:22
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
p.kill()

p.kill() kończy się zabiciem procesu powłoki i cmd nadal działa.

Znalazłem wygodną poprawkę:

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

Spowoduje to, że cmd odziedziczy proces powłoki, zamiast uruchamiać proces potomny, który nie zostanie zabity. p.pid będzie wtedy id twojego procesu cmd.

p.kill() powinno zadziałać.

Nie wiem, jaki to będzie miało wpływ na Twoją rurę.
 75
Author: Bryant Hansen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 15:24:24

Jeśli możesz użyć psutil , to działa idealnie:

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)
 34
Author: Jovik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-16 13:48:31

I could do it using

from subprocess import Popen

process = Popen(command, shell=True)
Popen("TASKKILL /F /PID {pid} /T".format(pid=process.pid))
To zabiło cmd.exe i program, dla którego wydałem polecenie.

(W Systemie Windows)

 17
Author: SPratap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-21 05:21:59

Gdy shell=True powłoka jest procesem potomnym, a polecenia są jego potomkami. Więc każdy SIGTERM lub SIGKILL zabije powłokę, ale nie jej procesy potomne, i nie pamiętam dobrego sposobu, aby to zrobić. Najlepszy sposób jaki mogę wymyślić to użycie shell=False, w przeciwnym razie, gdy zabijesz proces macierzysty powłoki, to pozostawi on nieistniejący proces powłoki.

 7
Author: Sai Venkat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-19 01:27:45

Żadna z tych odpowiedzi nie zadziałała dla mnie, więc zostawiam kod, który zadziałał. W moim przypadku nawet po zabiciu procesu za pomocą .kill() i uzyskaniu kodu zwrotnego .poll() proces nie został zakończony.

Po subprocess.Popen dokumentacja :

" ... aby prawidłowo wyczyścić dobrze zachowująca się aplikacja powinna zabić proces potomny i zakończyć komunikację..."

proc = subprocess.Popen(...)
try:
    outs, errs = proc.communicate(timeout=15)
except TimeoutExpired:
    proc.kill()
    outs, errs = proc.communicate()

W moim przypadku brakowało proc.communicate() Po wywołaniu proc.kill(). To oczyszcza proces stdin, stdout ... i kończy proces.

 5
Author: epinal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-11 14:25:29

Jak powiedział Sai, powłoka jest dzieckiem, więc sygnały są przez nią przechwytywane - najlepszym sposobem, jaki znalazłem, jest użycie shell=False i użycie shlex do podzielenia linii poleceń:

if isinstance(command, unicode):
    cmd = command.encode('utf8')
args = shlex.split(cmd)

p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

Następnie p. kill() I P.terminate () powinny działać zgodnie z oczekiwaniami.

 3
Author: Matt Billenstein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-25 04:53:19