Shell信号处理:捕捉进程信号实现脚本优雅终止

作者:袖梨 2026-07-08
Shell脚本可通过trap捕获SIGINT、SIGTERM等信号实现优雅退出,执行清理、日志记录等操作;需避免在处理函数中调用易中断命令或引发递归,并注意子shell不继承trap。

Shell脚本中,通过捕获信号(如 SIGINTSIGHUPSIGTERM)可以避免进程被粗暴中断,实现资源清理、日志记录、状态保存等优雅退出逻辑。

常用信号及其触发方式

脚本运行时可能收到的典型信号:

  • SIGINT(2):用户按 Ctrl+C 中断前台进程
  • SIGTERM(15):默认的 kill 命令发送的终止信号,用于请求正常退出
  • SIGHUP(1):终端断开或父进程退出时常见,常用于守护进程重载配置
  • SIGQUIT(3):按 Ctrl+ 触发,通常伴随核心转储,也可捕获做清理

使用 trap 捕获并处理信号

trap 是 Shell 内置命令,用于定义信号到达时执行的回调动作。基本语法为:
trap 'command' SIGNAL_NAMEtrap 'command' SIGNAL_NUMBER

  • 多个信号可合并处理:trap 'cleanup; exit 1' INT TERM QUIT
  • 用函数封装逻辑更清晰:
    cleanup() { echo "释放锁文件"; rm -f /tmp/myapp.lock; }<br>trap cleanup INT TERM
  • 注意单引号防止提前展开;若需变量插值,可用双引号但需谨慎转义

避免陷阱:常见误区与安全实践

信号处理看似简单,实际易出错:

  • 不要在 trap 处理器中调用可能被信号中断的复杂命令(如未加超时的 curlsleep),否则可能陷入不可中断状态
  • 避免在清理函数中再次触发相同信号(如递归调用 kill -TERM $$),引发死循环
  • 子 shell(如 (...))或管道中的命令不继承父 shell 的 trap,需显式传递或改用主流程控制
  • 若脚本以 set -e 运行,trap 不会自动取消该选项,建议在 cleanup 中明确处理错误路径

完整示例:带锁文件和日志的可中断循环

以下脚本模拟一个长期运行任务,支持安全中断并清理:

#!/bin/bashlockfile="/tmp/myscript.lock"<p>cleanup() {echo "[$(date)] 正在退出:清理资源..." >> /var/log/myscript.logrm -f "$lockfile"echo "已释放锁,退出。" >&2}</p><p>trap cleanup INT TERM</p><h1>创建锁文件</h1><p>if [ -e "$lockfile" ]; thenecho "锁文件存在,退出。" >&2exit 1fitouch "$lockfile"</p><h1>主逻辑:每5秒打印一次,直到被信号中断</h1><p>while true; doecho "运行中... PID: $$"sleep 5done

相关文章

精彩推荐