我在 bash 中使用Ctrl+做了 2 个关于 SIGINT 的测试。C
测试1
父脚本和子脚本都通过 来设置处理程序trap
。
# !/bin/bash
# Parent.sh
trap 'echo "I handled the SIGINT in Parent.sh and expect the script going ahead."' SIGINT
echo 1.1
./Child.sh
echo 1.2
# !/bin/bash
# Child.sh
trap 'echo "I handled the SIGINT in Child.sh and expect the script going ahead."' SIGINT
echo 2.1
sleep 1000000000
echo 2.2
/tmp:$ ./Parent.sh
1.1
2.1
^CI handled the SIGINT in Child.sh and expect the script going ahead.
2.2
I handled the SIGINT in Parent.sh and expect the script going ahead.
1.2
输出结果非常符合我的预期。
测试2
只有子脚本通过 设置处理程序trap
。
# !/bin/bash
# Parent.sh
# trap 'echo "I expect I will be terminated immediately after Child.sh died."' SIGINT
echo 1.1
./Child.sh
echo "sleep started"
sleep 5
echo "sleep finished"
echo 1.2
# !/bin/bash
# Child.sh
trap 'echo "I handled the SIGINT in Child.sh and expect the script going ahead."' SIGINT
echo 2.1
sleep 1000000000
echo 2.2
/tmp:$ ./Parent.sh
1.1
2.1
^CI handled the SIGINT in Child.sh and expect the script going ahead.
2.2
sleep started
sleep finished
1.2
我预计死后Parent.sh
应该立即终止(作为关于 SIGINT 的默认操作)Child.sh
。
但它似乎Parent.sh
收到了一个 SIGINT,但它忽略了它。
为什么会是这样呢?
答案1
发生这种情况是因为《等待并配合退出》(WCE)bash
实施。
当 bashSIGINT
在等待子进程时收到信号时,只有当子进程因该信号而死亡时(而不是子进程退出时),它才会自杀。父WIF*
进程可以根据子进程的退出状态确定它是由于未处理的信号而退出还是死亡 - 请参阅wait(2)
联机帮助页。
一个更简单的例子:
bash -c 'sh -c "trap exit INT; read p"; echo DONE'
<ctrl-C>
DONE
并与dash
shell,它不实现 WCE:
dash -c 'sh -c "trap exit INT; read p"; echo DONE'
<ctrl-C>
<no DONE, parent script was killed outright>