考虑以下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()函数。
答案 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,但这可能比它的价值更麻烦。