使用sleep infinity时无法捕获SIGINT与SIGTERM的问题排查
问题:Bash脚本无法捕获SIGINT/SIGTERM信号且进程不终止
脚本代码(testtrap.sh)
#!/bin/bash LOGFILE="/tmp/example.log" cleanup_function() { echo "Script interrupted by SIGINT, cleaning up..." >> $LOGFILE exit 0 } shutdown_function() { echo "Script terminated by SIGTERM, shutting down..." exit 0 } # Traps to handle SIGINT and SIGTERM trap 'cleanup_function' SIGINT trap 'shutdown_function' SIGTERM echo "Script running. It waits for SIGINT or SIGTERM..." >> $LOGFILE sleep inf
操作步骤
执行./testtrap.sh后,在另一个终端执行:
$ ps -A | grep testtrap.sh 28923 pts/2 00:00:00 testtrap.sh $ kill -s SIGINT 28923 $ kill -s SIGTERM 28923 $ ps -A | grep testtrap.sh 28923 pts/2 00:00:00 testtrap.sh
发现SIGINT和SIGTERM未被捕获,testtrap.sh进程也未终止。
问题原因
核心问题在于**sleep inf会让Bash脚本陷入无限等待子进程的状态**:
- 当脚本执行
sleep inf时,Bash会启动一个sleep子进程并进入阻塞状态,等待该子进程结束。 - 在Bash等待子进程期间,它会延迟处理SIGINT/SIGTERM信号,直到子进程退出。但
sleep inf是永远不会自行结束的,因此Bash永远没有机会触发你设置的trap函数,也无法终止。
另外,当你向Bash进程发送SIGINT/SIGTERM时,Bash会将信号转发给前台的sleep子进程,但如果系统中sleep实现对inf参数的处理异常(或忽略信号),也会导致子进程无法退出,进而Bash一直阻塞。
修复方案
将无限阻塞的sleep inf替换为循环短休眠,让Bash每隔一段时间就从休眠中返回,从而有机会处理信号:
#!/bin/bash LOGFILE="/tmp/example.log" cleanup_function() { echo "Script interrupted by SIGINT, cleaning up..." >> $LOGFILE exit 0 } shutdown_function() { echo "Script terminated by SIGTERM, shutting down..." exit 0 } # Traps to handle SIGINT and SIGTERM trap 'cleanup_function' SIGINT trap 'shutdown_function' SIGTERM echo "Script running. It waits for SIGINT or SIGTERM..." >> $LOGFILE # 用循环+短休眠替代sleep inf,让Bash能周期性处理信号 while true; do sleep 1 done
验证操作
- 执行修复后的脚本
./testtrap.sh - 在另一个终端找到进程ID并发送SIGINT:
$ ps -A | grep testtrap.sh 30125 pts/2 00:00:00 testtrap.sh $ kill -s SIGINT 30125
- 检查日志文件
/tmp/example.log,会看到Script interrupted by SIGINT, cleaning up...的记录,且进程已终止。
内容的提问来源于stack exchange,提问作者Francesco Galgani
相关产品推荐
相关产品推荐

