Linux后台脚本需用trap注册SIGTERM、SIGHUP、SIGINT信号处理器并执行cleanup后exit,避免默认粗暴终止导致资源泄漏;cleanup应杀子进程、删临时文件、记录日志;须注意子进程信号继承、trap后显式exit、sleep周期不宜过长、权限及systemd集成配置。

Linux后台脚本要可靠响应关闭信号(如 SIGTERM、SIGHUP、SIGINT),关键不是“拦截”信号,而是**注册信号处理器(trap)并做清理后优雅退出**。默认情况下,大多数脚本收到 SIGTERM 会直接终止,不执行收尾逻辑,容易导致资源泄漏或状态不一致。
用 trap 捕获关键信号并定义清理动作
trap 是 Shell 脚本中处理信号的核心机制。它允许你在指定信号到达时执行一段命令(通常是函数或内联命令)。常见需捕获的信号:
- SIGTERM(15):系统服务管理器(如 systemd、supervisord)停止服务时发送的默认信号,必须响应
- SIGHUP(1):终端断开或重载配置时可能触发,适合用于重载配置而非退出
- SIGINT(2):Ctrl+C 发送,开发调试时常用
示例:一个带清理逻辑的循环后台脚本
#!/bin/bash
<h1>清理函数:关闭子进程、删除临时文件、释放锁等</h1><p>cleanup() {
echo "[$(date)] Received shutdown signal, cleaning up..."</p><h1>杀掉可能 fork 的子进程(如后台 sleep、curl、tail -f)</h1><pre class="brush:php;toolbar:false;">pkill -P $$ 2>/dev/null
# 删除临时文件
rm -f /tmp/myscript.pid /tmp/myscript.lock
# 可选:记录退出状态到日志
echo "[$(date)] Clean exit." >> /var/log/myscript.log
exit 0}
注册信号处理器
trap cleanup TERM INT HUP
写 PID 文件(便于外部管理)
echo $$ > /tmp/myscript.pid
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
主逻辑:模拟长期运行任务(例如轮询、监听、定时工作)
while true; do
这里放你的实际业务逻辑,比如:
# check_health || break # process_queue # sleep 10 echo "[$(date)] Working..." >> /var/log/myscript.log sleep 30
done
避免常见陷阱
很多脚本看似加了 trap,却在实际环境中失效,原因常包括:
-
子进程未继承 trap 或忽略信号:bash 的 trap 不自动传递给子 shell 或外部命令。若主脚本启动了长时间运行的子进程(如
python server.py),应确保它自身也支持 SIGTERM,或用wait+kill显式管理 -
trap 后未 exit,导致脚本继续执行:trap 只是执行函数,不会自动终止。务必在 cleanup 函数末尾调用
exit -
信号被阻塞或覆盖:避免在循环中使用
sleep过长(如sleep 3600),因为信号可能被延迟响应;改用短周期 sleep 或wait -n(bash 4.3+)配合后台任务 - 权限问题导致清理失败:确保脚本以合适用户运行,能读写 PID 文件、日志、锁文件等路径
与 systemd 集成时的注意事项
如果脚本由 systemd 管理(推荐方式),需注意:
- service 文件中设置
Type=simple(默认)时,systemd 认为进程启动即就绪,此时trap TERM必须生效;设为Type=exec或Type=forking时行为不同,需匹配进程模型 - 建议添加
KillMode=control-group(默认),确保整个进程组被一并终止,避免子进程残留 - 可配置
ExecStop=/bin/kill -TERM $MAINPID,但更稳妥的是依赖脚本自身的 trap - 通过
systemctl stop myscript.service触发的就是 SIGTERM,验证是否触发 cleanup 最简单
测试信号响应是否有效
无需重启服务,可手动发送信号验证:
- 查 PID:
ps aux | grep myscript.sh或读取 PID 文件 - 发送 SIGTERM:
kill -TERM <pid></pid> - 观察日志:
tail -f /var/log/myscript.log是否输出 “cleaning up…” 和 “Clean exit.” - 检查残留:
ps --ppid <pid></pid>是否还有子进程,ls /tmp/myscript.*是否已清理










