Linux 中使用 trap 命令进行信号捕捉
在 Shell 脚本中,trap
是一个非常重要的内置命令,用于捕获信号(signals)并执行自定义的处理逻辑。它常用于实现脚本的优雅退出、资源清理、异常处理等。
🔧 什么是信号(Signal)?
信号是操作系统发送给进程的一种通知机制,用于告知进程发生了某种事件。例如:
- 用户按了
Ctrl+C
→ 发送SIGINT
信号 - 进程被强制终止 →
SIGKILL
- 脚本正常退出 → 触发
EXIT
(伪信号)
Shell 脚本可以通过 trap
捕获这些信号,并在收到信号时执行指定的命令。
📌 trap
命令语法
1 | trap 'command' SIGNAL [SIGNAL...] |
command
:当捕获到信号时要执行的命令(通常用引号包围)SIGNAL
:要捕获的信号名称或编号(如INT
,TERM
,EXIT
等)
🚩 常见信号及其含义
信号名 | 编号 | 触发方式 / 含义 |
---|---|---|
EXIT |
—— | 脚本正常退出前触发(不是系统信号,是 shell 提供的) |
SIGINT (INT ) |
2 | 用户按下 Ctrl+C |
SIGTERM (TERM ) |
15 | 正常终止请求(可被 trap 捕获) |
SIGKILL (KILL ) |
9 | 强制终止进程(不能被 trap 捕获) |
SIGSTOP |
17/19/23 | 暂停进程(不能被 trap 捕获) |
SIGQUIT (QUIT ) |
3 | 用户按下 Ctrl+\ |
ERR |
—— | 当命令执行失败(非零退出码)时触发(需启用) |
⚠️ 注意:
SIGKILL
和SIGSTOP
无法被 trap 捕获或忽略,因为它们是系统强制机制。
✅ 常用用法示例
1. 清理临时文件(使用 EXIT
)
1 | tempfile=/tmp/mytmp.$$ |
2. 捕获 Ctrl+C
(SIGINT
)
1 | trap 'echo "请不要中断!"; exit 1' INT |
运行时按 Ctrl+C
,不会立即退出,而是输出提示信息后退出。
3. 忽略信号(防止中断)
1 | trap '' INT # 忽略 Ctrl+C |
' '
表示空命令 → 忽略信号''
(两个单引号)表示空字符串 → 不执行任何操作
4. 同时捕获多个信号
1 | trap 'echo "正在退出..."; cleanup; exit 1' INT TERM EXIT |
5. 使用 ERR
捕获错误
1 | set -e # 遇到错误立即退出(可选) |
需要确保没有
set +e
关闭错误检查。
6. 取消防trap:trap - SIGNAL
1 | trap 'echo "退出中..."' EXIT |
这会恢复该信号的默认行为(即不执行任何处理)。
🔍 查看当前所有 trap
1 | trap |
输出示例:
1 | trap -- 'echo "退出..." ' EXIT |
⚠️ 注意事项
变量展开时机:
1
2trap "echo $PWD" EXIT # $PWD 在设置 trap 时就被展开了
trap 'echo $PWD' EXIT # $PWD 在触发时才展开(推荐用单引号)子 shell 不继承 trap:
在( ... )
子 shell 中,trap 不会自动继承,除非显式设置。SIGKILL 和 SIGSTOP 无法被捕获:
1
trap 'echo "不能阻止 kill -9"' KILL # ❌ 无效
函数中设置 trap 是局部的吗?
- 在函数中使用
trap
会影响整个脚本。 - 但可以结合
local
和trap
保存/恢复状态(高级用法)。
- 在函数中使用
🧩 实际应用场景
✅ 场景:安全删除临时目录
1 | TMPDIR=$(mktemp -d) |
✅ 场景:防止误中断
1 | trap 'echo "安装中,请勿中断!"; exit 1' INT TERM |
✅ 总结
写法 | 作用 |
---|---|
trap 'cmd' EXIT |
脚本退出前执行 cmd |
trap 'cmd' INT |
捕获 Ctrl+C |
trap 'cmd' TERM |
捕获 kill 命令 |
trap 'cmd' ERR |
命令失败时执行(需配合 set -e ) |
trap '' INT |
忽略中断信号 |
trap - INT |
恢复默认处理(取消 trap) |
trap |
显示当前所有 trap |
📌 最佳实践建议:
- 使用
trap ... EXIT
来清理资源(推荐) - 使用单引号避免变量过早展开
- 重要脚本中启用
ERR
和EXIT
trap 提高健壮性 - 不要试图捕获
SIGKILL
或SIGSTOP
(徒劳)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 萌小恩笔记!
评论
TwikooWaline