如何使用Python子进程终止进程组

如何使用Python子进程终止进程组,python,subprocess,kill,child-process,festival,Python,Subprocess,Kill,Child Process,Festival,我尝试使用Python子流程执行以下等效操作: >cat /var/log/dmesg | festival --tts & [1] 30875 >kill -9 -30875 请注意,我正在终止进程组(如进程ID号前面的负号所示),以便终止所有子进程 在Python中,我目前有以下代码,其中两个进程是通过管道创建和链接的 process_cat = subprocess.Popen([ "cat", "/var/log/dmesg" ], stdout =

我尝试使用Python子流程执行以下等效操作:

>cat /var/log/dmesg | festival --tts &
[1] 30875
>kill -9 -30875
请注意,我正在终止进程组(如进程ID号前面的负号所示),以便终止所有子进程

在Python中,我目前有以下代码,其中两个进程是通过管道创建和链接的

process_cat = subprocess.Popen([
    "cat",
    "/var/log/dmesg"
], stdout = subprocess.PIPE)
process_Festival = subprocess.Popen([
    "festival",
    "--tts"
], stdin = process_cat.stdout, stdout = subprocess.PIPE)
我应该如何以与上面显示的Bash方式相同的方式杀死这些进程及其子进程?以下方法是不够的,因为它不会终止子进程:

os.kill(process_cat.pid, signal.SIGKILL)
os.kill(process_Festival.pid, signal.SIGKILL)

有没有一种更优雅的方法可以做到这一点,也许只使用一个过程?

您可以简化这一点,因为您很少需要
cat
。例如:

process_Festival = subprocess.Popen(["festival", "--tts", "/var/log/dmesg"])
后来

process_Festival.send_signal(1)
如果你用SIGHUP而不是siggill这样的信号来扼杀节日 将正确清理所有子流程


有一个非常好的关于python子流程的解释。将选项
preexec\u fn=os.setsid
添加到Popen:

process_Festival = subprocess.Popen(["festival", "--tts", "/var/log/dmesg"],preexec_fn=os.setsid)
然后,您可以从进程id中获取进程组并向其发送信号:

pgrp = os.getpgid(process_Festival.pid)
os.killpg(pgrp, signal.SIGINT)

注意:由于Python 3.2,您还可以在
Popen
调用中使用
start\u new\u session=True
,而不是
preexec\u fn

为什么它不够?也许可以看看
os.setprgid
它是不够的,因为它不会杀死Festival的子进程。为了清楚起见,我将编辑这个问题。您好。谢谢你的简化建议。在这种情况下,您是完全正确的(尽管我想将管道用于其他更复杂的目的)。关于您的
send_signal(9)
方法,问题是这相当于
kill-9 30875
而不是
kill-9-30875
。您的方法不会杀死Festival创建的许多子进程,这正是我所需要的。有一个
os。killpg(pg,signal)
和process\u Festival.pid是进程id。不要使用kill-9,而是-1,这样Festival可以清理它的子进程。非常感谢您的建议。我需要杀死进程组,而不是让Festival终止子进程,因为子进程可以在终止之前继续运行很长时间,这不适合我的目的。您知道如何在子流程中使用
os.killpg
函数吗?它似乎不能与单个子流程返回的PID一起使用。我找到了一篇关于会话和流程组之间差异的好文章。因此,如果要生成守护进程,需要使用
os.setsid
start\u new\u session
参数。但是,如果您正在生成子进程,而这些子进程在您从终端注销时应该会死亡,则更愿意使用
preexec\u fn=os.setpgrp