Linux Shell杀死信号SIGKILL和KILL

3

我刚写了一个shell脚本来控制模块的启动和停止。一切似乎正常,直到我发现停止命令导致了意外情况。

我使用kill -s SIGKILL -- -gpid命令来杀死一组进程。我使用/bin/sh运行这个命令,像这样:

/bin/sh -c "kill -s SIGKILL -- -gpid"

回复的错误如下:

/bin/sh: 行 0: kill: SIGKILL: 无效的信号规范

然后我将/bin/sh替换为/bin/bash,所以命令变成了:

/bin/bash -c "kill -s SIGKILL -- -gpid"

它没有返回任何错误信息,因此我得出结论是bash和sh之间的差异导致了结果不同。然而,当我使用ls命令查看/bin/sh时,我发现/bin/sh是指向/bin/bash的符号链接,所以这两个命令应该是相同的。

我发现kill -s SIGKILL命令语法不符合推荐的语法,应该使用kill -s KILL命令。

因此,我将SIGKILL替换为KILL,命令如下:

/bin/sh -c "kill -s KILL -- -gpid"

回复了空错误。正如上面所述,任何人都可以解释这种情况。


你用的是哪个发行版?在我的Ubuntu 12.04上,/bin/sh实际上指向/bin/dash。你的情况也可能是一样的,你读到的是bash,但实际上是dash吗? - Shahbaz
5
当以 sh 的方式调用 bash(例如通过符号链接,就像你的情况一样)时,它会使用与 sh 兼容的模式,其中大多数现代特性都被关闭。我敢打赌 sh 正在调用 kill 的外部二进制文件,并且它不识别 SIGKILL,但是 bash 调用却使用了其内置的命令,而该内置命令则识别 SIGKILL - Kevin
@Kevin,bash是通过检查它的argv[0]来执行这个操作的吗? - Shahbaz
1
你不应该使用SIGKILL(-9),而应该使用SIGTERM(-15)、SIGINT或SIGHUP。当你使用SIGKILL时,程序无法正确关闭自身,无法删除临时文件,无法关闭套接字,也无法向其子进程发送信号... - clt60
@Shahbaz 是的,它检查 argv[0] - Kevin
显示剩余2条评论
3个回答

4
唯一真正可移植的编写此命令的方法是:
kill -9 -$gpid

没有一种方法能够指定信号的名称而不是信号编号,这对于上世纪90年代中期已经冻结其shell工具的Unix系统而言都不起作用,基本上所有除了Linux和开源BSD之外的Unix系统都是如此。但是,SIGKILL始终是可靠的信号编号9,并且一直是这样(自V7以来)。

--这个特殊参数也不具备可移植性,在这种情况下是不必要的。

如果您想更加礼貌地做到这一点(发送SIGTERM),那么请使用

kill -15 -$gpid

再次强调,这个数字一直可靠,可以追溯到V7版本。


3
当bash以sh被调用时(例如通过符号链接,就像您的情况一样),它使用sh兼容模式,其中大多数现代功能被关闭。我敢打赌sh正在调用kill的外部二进制文件,它不认识SIGKILL,但是bash调用正在使用其内置命令,并且该内置命令是可用的。

听起来不错。有没有办法检查外部kill和内置kill之间的差异,或者有没有一种方法可以跟踪我提到的命令执行的进度。 - Red Lv
我发现它并不像上面描述的那样工作,因为你可以使用命令“enable -n kill”禁用内置的kill,然后执行“kill -s SIGKILL pid”,这也可以起作用。所以我猜这里肯定有些事情没有被提到。 - Red Lv

2

这都与bash兼容性有关。快速解决方法是使用/bin/bash,因为sh无法识别SIGINT或其他特性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接