Отправить сигнал всем процессам в группе

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

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

Тем не менее, когда я пытаюсь убить с помощью:

p.terminate()

или же

p.kill()

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

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

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

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

 Robert Siemer27 нояб. 2014 г., 16:47
Что делает твойcmd выглядит как? Может содержать команду, запускающую несколько процессов. Так что не ясно, о каком процессе вы говорите.
 Charlie Parker07 мар. 2019 г., 20:46
не имеяshell=True иметь большое значение?

Ответы на вопрос(10)

оболочка является дочерней, поэтому она перехватывает сигналы - лучший способ, который я нашел, это использовать shell = False и использовать shlex для разделения командной строки:

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

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

Тогда p.kill () и p.terminate () должны работать так, как вы ожидаете.

 Matt Billenstein26 янв. 2011 г., 07:27
Используйте абсолютные пути вместо смены каталогов ... При желании os.chdir (...) в этот каталог ...
 hungryWolf25 янв. 2017 г., 06:46
Я использовал shlex, но проблема остается, kill не убивает дочерние процессы.
 Jonathon Reinhart17 авг. 2015 г., 03:22
Возможность изменить рабочий каталог для дочернего процесса является встроенной. Просто передайтеcwd аргументPopen.
 user17525926 янв. 2011 г., 00:00
В моем случае это не очень помогает, учитывая, что cmd - это «путь к CD && zsync и т. Д.». Так что на самом деле команда терпит неудачу!

Если вы можете использовать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)
 Jovik22 сент. 2015 г., 16:20
@Godsmith - API psutil изменился, и вы правы:дети() делает то же самое, что и get_children (). Если это не работает в Windows, то вы можете захотеть создать сообщение об ошибке вGitHub
 d33tah13 июл. 2015 г., 23:47
AttributeError: 'Process' object has no attribute 'get_children заpip install psutil.
 benjammin04 февр. 2015 г., 22:30
Это в конечном итоге работает для меня на Windows.
 Godsmith18 сент. 2015 г., 14:51
Я думаю, что get_children () должен быть children (). Но это не работает для меня в Windows, процесс все еще там.

shell=True оболочка - это дочерний процесс, а команды - его дочерние. Так что любойSIGTERM или жеSIGKILL убьет оболочку, но не ее дочерние процессы, и я не помню хорошего способа сделать это. Лучший способ придумать - это использоватьshell=Falseиначе, вы убьете родительский процесс оболочки, он покинет несуществующий процесс оболочки.

поэтому я оставляю код, который работал. В моем случае даже после убийства процесса с.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 ... и завершает процесс.

 xyz07 дек. 2018 г., 13:59
Это решение не работает для меня в Linux и Python 2.7
 xyz10 дек. 2018 г., 21:56
@ espinal, спасибо, да. Возможно, это проблема Linux. Это Raspbian Linux работает на Raspberry 3
 epinal10 дек. 2018 г., 17:44
@xyz Это сработало для меня в Linux и Python 3.5. Проверьте документы для Python 2.7
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() должно сработать.

Я не знаю, какое влияние это окажет на вашу трубу.

 gnr02 дек. 2017 г., 00:34
это не работает, если в cmd используется точка с запятой
 speedyrazor21 мая 2014 г., 16:43
Работает ли это на Windows и MAC.
 Sergiy Kolodyazhnyy25 авг. 2016 г., 05:35
Это прекрасно. Я пытался выяснить, как порождать и убивать подпроцесс для каждого рабочего пространства в Ubuntu. Этот ответ помог мне. Жаль, что я мог бы поднять это не раз
 Nicolinux04 авг. 2016 г., 19:51
Очень хорошее решение. Если ваш cmd оказывается оболочкой сценария оболочки для чего-то еще, вызовите последний двоичный файл там тоже с помощью exec, чтобы иметь только один подпроцесс.
 MarSoft24 авг. 2015 г., 16:10
Хорошее и легкое решение для * nix, спасибо! Работает на Linux, должен работать и на Mac.
Решение Вопроса

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

Вот код:

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
 Zang MingJie29 авг. 2012 г., 11:52
preexec_fn=os.setpgrp также работает
 hwjp10 июн. 2013 г., 17:16
наше тестирование предполагает, что setsid! = setpgid и os.pgkill убивают только подпроцессы, которые все еще имеют тот же идентификатор группы процессов. процессы, которые изменили группу процессов, не уничтожаются, даже если они могут иметь одинаковый идентификатор сеанса ...
 Piotr Dobrogost19 окт. 2012 г., 12:53
Какsubprocess.CREATE_NEW_PROCESS_GROUP относитесь к этому?
 Piotr Dobrogost19 окт. 2012 г., 01:06
Это работает на Windows?

что я чувствую, что мы могли бы использовать:

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

os.killpg(os.getpgid(pro.pid), signal.SIGINT)

это не убьет всю вашу задачу, но процесс с p.pid

Отправить сигнал всем процессам в группе

    self.proc = Popen(commands, 
            stdout=PIPE, 
            stderr=STDOUT, 
            universal_newlines=True, 
            preexec_fn=os.setsid)

    os.killpg(os.getpgid(self.proc.pid), signal.SIGHUP)
    os.killpg(os.getpgid(self.proc.pid), signal.SIGTERM)

что это старый вопрос, но это может помочь кому-то искать другой метод. Это то, что я использую в Windows, чтобы убить процессы, которые я вызвал.

si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.call(["taskkill", "/IM", "robocopy.exe", "/T", "/F"], startupinfo=si)

/ IM - это имя изображения, вы также можете сделать / PID, если хотите. / T убивает процесс, а также дочерние процессы. / F сила прекращает это. Си, как я установил, это то, как вы делаете это, не показывая окно CMD. Этот код используется в Python 3.

Я мог бы сделать это с помощью

from subprocess import Popen

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

это убилоcmd.exe и программа, для которой я дал команду.

(В Windows)

 Steven Xu06 февр. 2015 г., 06:31
Это работает для окон. Спасибо!

Ваш ответ на вопрос