echo
给定一个在接收到SIGSTOP
or信号时的脚本SIGHUP
:
$cat test.sh
function clean_up {
echo "cleaning up!"
}
echo 'starting!'
trap clean_up SIGSTOP SIGHUP
sleep 100
我在后台运行它:
$./test.sh > output &
[4] 42624
然后,我用-1
ie杀死了它叹息
$kill -1 42624
但它trap
没有按我的预期工作,即该output
文件没有cleaning up!
内容。
$cat output
starting!
发生了什么?
答案1
答案2
实际上它确实打印了,但你必须等待 100 秒才能看到结果。
你说:
$./test.sh > output &
[4] 42624
如果你检查ps aux
,你会得到类似的内容:
xiaobai 42624 0.0 0.1 118788 5492 pts/3 S 04:07 0:00 /bin/bash
xiaobai 42626 0.0 0.0 108192 668 pts/3 S 04:07 0:00 sleep 100
你的主脚本进程/bin/bash,PID 42624仍在等待sleep 100完成。即使主进程收到信号1,它也必须sleep 100
先等待完成,然后才轮到它执行任务,即echo "cleaning up!"
。
您可以使睡眠进程成为后台进程。在这种情况下,当且仅当脚本进程尚未退出时,脚本进程可以执行而echo "cleaning up!"
无需等待。sleep process
我们可以通过这个脚本证明概念(即脚本sleep
在处理信号之前等待):
function clean_up {
echo "cleaning up!"
}
echo 'starting!'
trap clean_up SIGHUP
sleep 5000 &
echo 1
sleep 20
echo 2
sleep 10
echo 3
像往常一样运行这个脚本./test.sh > output
,然后使用ps aux
来找出/bin/bash
PID 是 23311,然后执行kill -1 23311
.同时cat output
要知道这个阶段,即当脚本进入sleep 20
echo 1 之后,发送kill -1 23311
,现在等待 2 出来,你会发现“cleaning up”已经在 2 之前一起打印了。最后轮到echo 3
脚本了出口。
$ cat output
starting!
1
cleaning up!
2
3
$
上面的实验证明,脚本接收 SIGHUP 信号并在所有前面的前台进程完成后执行信号处理程序,而无需等待后台进程。
故事变得有趣了,有了你原来的剧本,如果你这么做了怎么办kill -1 PID_of_sleep_100
?
它将退出所有进程而不打印,因为睡眠进程不会向脚本进程返回 SIGHUP。
因此,您的任务有一个解决方案,您可以执行kill -1 PPID
(脚本进程)来确认 SIGHUP 到脚本进程,然后kill -1 PID
(睡眠进程)。现在脚本进程将在退出之前执行 SIGHUP 处理程序,快乐黑客:)
并非所有信号都相同,例如SIGKILL 不允许陷阱。如果您杀死 -9 脚本进程,则睡眠进程仍将运行,并且其父 PID 将变为 1(通过检查ps -ef
)。
[更新]:
通常情况下kill -N script_PID
下会如果信号 N 没有捕获到您的脚本中,则直接终止脚本。但要小心 SIGINT,kill -2 script_PID
即使你的脚本没有捕获它,它也不会直接杀死它。您的脚本将等待您的子进程(例如 sleep 10)完成。现在假设您在 script_PID 中执行多次终止,即kill -2 script_PID
AND kill -user-defined_trap_N script_PID
,然后:
- 如果睡觉等待10秒后正常返回或者通过 2 以外的信号杀死,您的脚本在返回时将忽略缓存的信号2,然后执行用户定义的_trap_N函数。
- 但如果睡觉信号2杀死,那么你的脚本将在返回时执行内置的SIGINT处理程序,然后直接kill而不执行user-defined_trap_N。