<p>Shell脚本需通过trap有选择地捕获SIGINT、SIGTERM、EXIT等信号执行清理,临时屏蔽信号用trap ” SIGNAL,临界区后须用trap – 恢复;SIGHUP影响取决于前台/后台及会话关联,推荐nohup/setsid守护。</p>

Shell脚本在运行中常因意外信号(如 Ctrl+C 触发的 SIGINT、终端关闭引发的 SIGHUP)而中断,导致资源未释放、临时文件残留或状态不一致。要提升鲁棒性,关键不是完全禁用信号,而是**有选择地屏蔽、捕获和安全响应**。
用 trap 捕获关键信号并执行清理
trap 是 Shell 处理信号的核心机制。它允许你在指定信号到达时运行一段命令(通常是函数),特别适合做退出前的清理工作。
- 语法:
trap 'command' SIGNAL_NAME或trap function_name SIGNAL_NAME - 常用信号:SIGINT(中断)、SIGTERM(终止)、EXIT(脚本退出时,无论是否出错)
- 推荐始终捕获
EXIT:确保无论成功失败都执行清理
示例:
cleanup() {
rm -f /tmp/myapp.pid /tmp/myapp.lock
echo "Cleanup done." >&2
}
trap cleanup EXIT SIGINT SIGTERM
临时屏蔽信号:用 SIGUSR1/SIGUSR2 做协调开关
Shell 本身不支持传统意义上的“信号掩码”(如 C 的 sigprocmask),但可通过 trap '' SIGNAL 实现**临时忽略**某信号——这在临界区(如写配置、更新符号链接)中很实用。
-
trap '' SIGINT:暂时忽略 Ctrl+C,避免中断敏感操作 - 操作完成后务必恢复:
trap - SIGINT(-表示恢复默认行为) - 注意:不要长期屏蔽 SIGTERM/SIGHUP,否则无法被正常管理(如 systemd stop)
示例(原子更新):
update_config() {
trap '' SIGINT SIGTERM # 进入临界区
cp config.new config.tmp
mv config.tmp config
trap - SIGINT SIGTERM # 恢复信号响应
}
区分前台/后台行为:SIGHUP 的实际影响
当终端关闭或 ssh 断连时,Shell 默认向子进程发送 SIGHUP。但行为取决于进程是否与终端关联:
- 前台作业:直接收到 SIGHUP,通常退出
- 后台作业(含
&启动):若未脱离会话,仍可能被 hangup - 真正可靠的后台守护方式:用
nohup、setsid或重定向/dev/null并忽略 SIGHUP
安全写法:
# 启动后自动忽略 SIGHUP,并重定向 I/O nohup ./worker.sh > /var/log/worker.log 2>&1 < /dev/null &
避免常见陷阱
信号处理看似简单,但几个细节极易引发问题:
-
trap中禁止调用可能被信号中断的复杂命令(如未加锁的echo到同一文件多次) - 不要在 trap 函数里
exit非 0 值来“模拟错误”——它不会改变脚本最终退出码,反而干扰调用方判断 - 子 shell(
(...))中的trap不继承父 shell,需显式设置 - 使用
set -e时,trap不会因命令失败自动触发,必须靠信号或显式exit
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/jiquanzatan/123726.html