linux脚本安全退出需用trap在开头捕获sighup、sigint、sigterm信号并执行cleanup:sighup因终端断开触发,sigint对应ctrl+c,sigterm是kill标准终止信号;cleanup中应显式exit,避免子进程残留,返回130/143等规范退出码。

Linux信号机制在脚本中实现安全退出,核心是用 trap 捕获关键信号(如 SIGHUP、SIGINT、SIGTERM),并在收到信号时执行预定义的清理逻辑,而不是让脚本突然终止。
必须捕获的三个信号及其典型触发场景
高并发或长期运行的 Shell 脚本最常因以下情况意外中断:
- SIGHUP:SSH 连接断开、终端关闭、systemd 服务重启时默认发送;不捕获会导致子进程残留、锁文件未释放
-
SIGINT:用户按
Ctrl+C,属于主动中断,需响应但不能直接退出 -
SIGTERM:外部调用
kill PID或容器停止时的标准终止信号,应作为“优雅退出”的主入口
trap 注册必须放在脚本最开头
一旦启动后台任务(如 some_cmd &),再注册 trap 就可能错过信号。正确写法是:
#!/bin/bash
cleanup() {
echo "正在清理临时文件和子进程..."
rm -f /tmp/myapp.lock
kill $! 2>/dev/null # 终止最后启动的后台进程
wait $! 2>/dev/null
}
trap cleanup HUP INT TERM # 必须在任何 & 或子进程前
注意:$! 只能捕获上一个后台进程 PID,若需管理多个子进程,建议记录 PID 到数组或文件,并在 cleanup 中统一 kill。
避免常见陷阱:子进程信号继承与隔离
默认情况下,用 & 启动的后台命令仍属于当前会话,会随父进程收到 SIGHUP 而被影响。解决方法有:
- 对必须长期运行的子任务,用
nohup cmd &或setsid cmd &隔离信号,但要确保它们不干扰主脚本的生命周期 - 不要在 cleanup 中依赖
exit——trap处理函数执行完后,脚本默认继续运行;若需退出,显式写exit 0或exit 1 - 慎用
kill -9:仅当子进程完全无响应时使用;正常清理应优先发SIGTERM并等待几秒,再考虑强制终止
配合退出码体现退出原因
脚本结束前返回明确退出码,方便上游判断结果:
-
exit 0:正常完成或被信号优雅终止 -
exit 128+2(即 130):表示被SIGINT(Ctrl+C)中断 -
exit 128+15(即 143):表示被SIGTERM终止 - 自定义错误码如
exit 5表示资源清理失败等内部异常
父进程可通过 $? 获取该值,用于自动化流程控制。











