来自the POSIX standard for the shell:
如果在 shell 等待执行前台命令的实用程序完成时接收到已设置陷阱的信号,则在前台命令完成之前,不应执行与该信号关联的陷阱。
为了验证这一点,我们可以在执行脚本的 shell 上运行 strace。在从另一个终端发送SIGINT 后,bash 只是注意到信号已被接收并返回等待其子进程 sleep 命令完成:
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) = ?