为什么使用source执行bash脚本时SIGINT陷阱无法生效
问题原因解释
两种执行方式的核心差异是脚本运行的进程上下文不同,具体逻辑如下:
1. bash script.sh/./script.sh执行时trap生效的原因
- 这两种执行方式都会启动一个独立的非交互式bash子进程来运行整个脚本
- 按下Ctrl+C发送的
SIGINT信号会直接递交给这个子进程 - 子进程内提前注册的
trap规则匹配到SIGINT,就会触发no_ctrlc函数执行,函数内的exit会终止当前子进程,回到父级交互式shell,符合预期表现。
2. source script.sh执行时trap不生效的原因
source是在当前正在使用的交互式bash进程内逐行执行脚本内容,不会创建新的子进程,trap规则实际是注册在你当前用的终端shell上- 你观察到的无响应现象和
sleep 5这个外部命令的执行逻辑直接相关:- 交互式bash运行外部命令时,会暂时将前台进程组权限交给
sleep进程,自身退到后台等待外部命令执行结束 - 按下Ctrl+C时,
SIGINT只会发送给当前前台进程组的sleep进程,sleep收到信号后直接终止退出,退出码为130 - 交互式bash收回前台控制权后,会默认忽略本次伴随前台命令终止产生的
SIGINT(这是交互式shell的默认设计:如果每次打断前台命令都触发shell自身的trap,那你日常打断ping/grep等命令时都可能触发shell的自定义规则甚至直接退出终端,完全不符合使用预期) - 外层
while true判断条件始终为真,会直接进入下一轮循环,因此你会看到Ctrl+C仅打断了当前的sleep,trap函数完全不会触发,看起来就像Ctrl+C失效了。
- 交互式bash运行外部命令时,会暂时将前台进程组权限交给
补充验证:你可以把脚本内的
sleep 5替换成内置命令:(空操作)再执行source script.sh,此时按下Ctrl+C会直接触发trap函数,甚至会因为exit直接退出当前终端,就是因为此时没有前台外部命令,bash自身会处理收到的SIGINT信号。
内容的提问来源于stack exchange,提问作者Limone
相关产品推荐
相关产品推荐

