Python linux-信号未传递给multi命令

Python linux-信号未传递给multi命令,python,linux,bash,shell,Python,Linux,Bash,Shell,我试图理解为什么在这种设置下信号传递不正确。 简单的测试,我有一个python脚本,它注册了一个sigterm处理程序,并在得到它时打印出来。如果我运行它并发送一个术语,我已经验证了它的有效性 但是,我碰巧将其作为一个python子进程运行,useShell=True。useShell使用/bin/sh-c启动命令 如果我这样做,它实际上也会起作用: $/bin/sh -c "python ~/tmpcode/signal_test.py" & [8] 6207 $ kill 6207

我试图理解为什么在这种设置下信号传递不正确。 简单的测试,我有一个python脚本,它注册了一个sigterm处理程序,并在得到它时打印出来。如果我运行它并发送一个术语,我已经验证了它的有效性

但是,我碰巧将其作为一个python子进程运行,useShell=True。useShell使用/bin/sh-c启动命令

如果我这样做,它实际上也会起作用:

$/bin/sh -c "python ~/tmpcode/signal_test.py" &
[8] 6207
$ kill 6207
 signum 15
但是,我有一些脚本可以执行链接命令,即/foo/bar.sh;一些其他脚本.py。在这种情况下,信号不会传递给最终脚本:

$ /bin/sh -c "echo foo; python ~/tmpcode/signal_test.py" &
[8] 8015
$ kill 8015
如果我尝试&&而不是; 我试图了解这里发生了什么,以及是否有办法让信号传递出去。 旁白:脚本运行多链命令的主要原因是第一个命令为第二个命令设置了一些要使用的环境

信号_test.py:

import time
import signal
import sys

def handler( signum, frame ):
    print( "signum %d\n" % signum ) 
    sys.exit(signum)

signal.signal( signal.SIGTERM, handler )
time.sleep(60)

让我解释一下细节

bash返回的数字不是pid,而是pgid(进程组id) 在shell中运行命令时,shell将创建一个新的进程组。该组将包含命令中的所有进程。pgid与leader进程的pid相同

进程组表示多任务。在单词multi task中,shell可以使用bg(^Z)/fg在组之间切换。shell(实际上是另一个故事)生成的所有信号(如^C)将发送给整个小组,而不是领导进程

shell何时创建多个进程或单个进程? 答案显然是,当命令不能由单个进程处理时,shell将创建多个进程

在第一个例子中 只发出一个命令,子shell本身(
/bin/sh
)就变成了
python
。请注意,即使只有一个流程,也会有一个新的流程组包含唯一的流程

在第二个例子中 发出两个命令,单进程无法完成任务,需要多进程:

/bin/sh
    echo
    python
将创建一个包含这三个流程的流程组

如何向进程组发送信号? 使用

杀死-
pgid前面的减号很重要。

让我解释一下细节

bash返回的数字不是pid,而是pgid(进程组id) 在shell中运行命令时,shell将创建一个新的进程组。该组将包含命令中的所有进程。pgid与leader进程的pid相同

进程组表示多任务。在单词multi task中,shell可以使用bg(^Z)/fg在组之间切换。shell(实际上是另一个故事)生成的所有信号(如^C)将发送给整个小组,而不是领导进程

shell何时创建多个进程或单个进程? 答案显然是,当命令不能由单个进程处理时,shell将创建多个进程

在第一个例子中 只发出一个命令,子shell本身(
/bin/sh
)就变成了
python
。请注意,即使只有一个流程,也会有一个新的流程组包含唯一的流程

在第二个例子中 发出两个命令,单进程无法完成任务,需要多进程:

/bin/sh
    echo
    python
将创建一个包含这三个流程的流程组

如何向进程组发送信号? 使用

杀死-
pgid前面的减号很重要。

这是因为Python进程将具有不同的进程id。@user902384没有解释
signal\u test.py
如何获取第一个问题中的信号。但是在第一个示例中,
sh
可能会优化为使用
exec
来运行单个指定的命令,意思是6207是Python进程。在第二个示例中,
sh
为Python提供了一个新的进程。(如果您显示
signal_test.py
的内容,我们可能会建议如何确认这一假设。)也可能有助于查看
ps-fu$LOGNAME
,以及
trap
@ByteMe95
kill 6207
(将SIGTERM发送到进程)如何通过您的脚本(只为SIGKILL安装处理程序)得到处理?这是因为Python进程将有一个不同的进程id。@user902384没有解释
signal\u test.py
如何在第一个问题中获取信号。但是在第一个示例中,
sh
可以优化为使用
exec
运行单个指定的命令,这意味着6207是Python进程。在第二个示例中,
sh
为Python提供了一个新的进程。(如果您显示
signal_test.py
的内容,我们可能会建议如何确认这一假设。)也可能有助于查看
ps-fu$LOGNAME
,以及
trap
@ByteMe95
kill 6207
(将SIGTERM发送到进程)如何通过您的脚本(只为SIGKILL安装处理程序)得到处理?我不认为有任何要求要求shell检测何时可以简单地执行而不是分叉;这是一个依赖于实现的优化(可以使用
strace
或类似方法来确认)。@chepner也许我的答案有点误导,但我的观点是,您应该始终将数字视为pgid而不是pid。我根本不在乎有多少道工序,这很公平。向进程组发送信号意味着每个进程直接从操作系统接收信号,而不是由组长将信号传递给其子进程,对吗?(这是一个微妙的区别,但这意味着,除其他外,组长不能决定谁接收到信号。)我认为没有任何要求要求外壳检测何时可以简单地执行而不是分叉;这是一个依赖于实现的优化(可以使用
strace
或类似方法来确认)。@chepner-may
/bin/sh
    echo
    python
kill <SIGNAL> -<pgid>