Kill -INT不使用陷阱INT设置的bash脚本

时间:2017-11-05 08:53:31

标签: bash shell unix signals kill

考虑以下bash脚本s

#!/bin/bash
echo "Setting trap"
trap 'ctrl_c' INT
function ctrl_c() {
        echo "CTRL+C pressed"
        exit
}
sleep 1000

调用./s时,它会睡觉。如果按Ctrl + C,则会打印该消息并退出。

现在打电话给它,打开另一个终端并杀死相应的bash pid -INT标志。它不起作用或做任何事情。为什么呢?

Kill without flags无效但不调用ctrl_c()函数。

3 个答案:

答案 0 :(得分:1)

来自the POSIX standard for the shell

  

当shell等待执行前台命令的实用程序完成时,如果接收到已设置陷阱的信号,则在前台命令完成之前,不应执行与该信号关联的陷阱。

要验证这一点,我们可以在执行脚本的shell上运行strace。从另一个终端发送SIGINT后,bash只是注意到已收到信号并返回等待其子节点睡眠命令完成:

rt_sigaction(SIGINT, {0x808a550, [], 0}, {0x80a4600, [], 0}, 8) = 0
waitpid(-1, 0xbfb56324, 0)              = ? ERESTARTSYS
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=3556, si_uid=1000} ---
sigreturn({mask=[CHLD]})                = -1 EINTR (Interrupted system call)
waitpid(-1, 

要使kill Ctrl-C 具有相同的效果,您应该将SIGINT发送到进程组。默认情况下,shell会将新命令的每个进程放入其自己的pgrp:

$ ps -f -o pid,ppid,pgid,tty,comm -t pts/1
  PID  PPID  PGID TT       COMMAND
 3460  3447  3460 pts/1    bash
29087  3460 29087 pts/1     \_ foo.sh
29120 29087 29087 pts/1         \_ sleep

$ kill -2 -29087

现在陷阱运行并且shell退出:

waitpid(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGINT}], 0) = 29120
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=3556, si_uid=1000} ---
sigreturn({mask=[CHLD]})                = 29120
...
write(1, "CTRL+C pressed\n", 15)        = 15
...
exit_group(0)                           = ?

答案 1 :(得分:0)

当我们使用ps aux命令查找PID值时,我们看到有2个进程,这个程序和sleep。正如你所说,程序进程不会使用-INT参数中断。但是,当-2或-INT(相同含义)参数用于睡眠过程时,过程会按预期中断。消息打印和退出。我不明白为什么主进程没有停止,但我想表明睡眠过程可以被这种方法中断。我希望这对你有好处。

答案 2 :(得分:0)

sleep不是内置的shell:

$ which sleep
/bin/sleep

这意味着当您运行sleep时,它将作为单独的子进程运行。创建子进程时,会将各种内容从父级复制到子级(继承),其中一种是信号掩码。注意:只有面具。所以如果你设置了:

 trap '' INT

然后sleep将继承 - 它意味着忽略信号。但是,在您的情况下,您希望sleep(可能用C编写)来执行bash函数。没有办法 - 错误的语言一开始。想象一下:它必须执行bash来执行bash函数。

警告 - 有关信号处理的详细信息可能因平台而异。

可以将sleep作为内置版本,请参阅here,但这可能比它的价值更麻烦。