为何向Bash脚本发送TERM信号时会触发ERR陷阱?
问题根源与解决办法
你遇到的问题核心是Bash版本差异导致的陷阱行为不同:Ubuntu 14.04搭载的是Bash 4.3,而Scientific Linux 7.3用的是Bash 4.2,这两个版本对ERR陷阱的触发逻辑有关键区别:
- 在Bash 4.3+中,
ERR陷阱仅在命令自身执行出错(非信号导致的非零退出码)时触发; - 但在Bash 4.2中,任何命令的非零退出码都会触发
ERR陷阱——包括命令被信号终止的情况(比如SIGTERM杀死sleep这类前台进程)。
当你给脚本发SIGTERM时,脚本的前台子进程(比如你脚本里可能在运行的耗时命令)会先收到信号并退出,退出码是128+15=143(15是SIGTERM的信号编号)。在Bash 4.2中,这个非零码会立刻触发ERR陷阱,而脚本自身的SIGTERM陷阱还没来得及执行,脚本就因为ERR陷阱里的exit 1直接退出了,所以你看到的是ERR陷阱的输出。
解决办法
1. 让ERR陷阱忽略信号导致的退出
我们可以通过判断退出码是否≥128(信号导致的退出码都是128+信号编号),来跳过ERR陷阱的处理:
trap 'EXIT_STATUS=$? # 仅处理非信号导致的错误 if [ "$EXIT_STATUS" -lt 128 ]; then echo "caught error (exit status: $EXIT_STATUS)" exit 1 fi' ERR
2. 优化SIGTERM陷阱,先清理子进程再退出
修改SIGTERM陷阱,先捕获信号输出信息,再终止脚本的所有子进程,避免子进程退出触发ERR陷阱:
trap 'echo "caught signal SIGTERM" # 杀死当前脚本的所有子进程 pkill -P $$ exit 1' SIGTERM
pkill -P $$会精准杀死父进程为当前脚本PID的所有子进程,确保子进程不会因为SIGTERM退出而触发ERR陷阱。
3. (可选)用信号编号替代信号名
少数系统对信号名的解析可能有差异,你可以试试用SIGTERM的信号编号15来设置陷阱:
trap 'echo "caught signal SIGTERM"; exit 1' 15
修改后在Scientific Linux 7.3上测试,发送SIGTERM信号应该会正常触发SIGTERM陷阱了。
内容的提问来源于stack exchange,提问作者Menachem Sklarz
相关产品推荐
相关产品推荐

