模块:S11 信号、陷阱与健壮性
篇号:S11-01 / 42
预计阅读:45 分钟
主线:Bash
文章目录
- 本篇目标
- 30 秒速览
- 正文
- 1. 为什么需要 `trap`
- 2. 基本语法
- 3. `EXIT`:最常用
- 4. 临时文件标准模式
- 5. `INT` 与 `TERM`:优雅退出
- 6. 忽略与恢复信号
- 7. `ERR`(Bash + 常配合 `set -e`)
- 8. `RETURN`(Bash,函数返回时)
- 9. `trap` 字符串与引号
- 10. 与 `set -e`、`exit` 的关系
- 11. 读脚本时的常见片段
- 11.1 锁文件
- 11.2 子进程与 trap
- 11.3 被 source 的库
- 12. 注意点小结
- 读脚本检查清单
- 练习
- 判断题
- 实操题
- 改错题
- 下一篇预告
本篇目标
掌握trap:在脚本收到信号或退出时执行清理命令。会写trap cleanup EXIT、处理Ctrl+C(INT)、TERM,配合mktemp删除临时文件,并理解ERR/RETURN(Bash)的适用场景。读完能读懂运维脚本里的「无论成功失败都清理」写法。
30 秒速览
- 信号:内核/终端发给进程的异步通知(如INT中断、TERM终止)。
trap '命令' 信号列表:收到信号或事件时执行命令(字符串形式)。EXIT:Shell退出时触发(成功、exit、set -e失败均可),适合做清理。- 临时文件:
tmp=$(mktemp)后trap 'rm -f "$tmp"' EXIT。 - 忽略信号:
trap '' INT;恢复默认:trap - INT。 trap处理器里慎用exit,可能打断其它清理。
正文
1. 为什么需要trap
脚本可能:
- 被Ctrl+C打断
- 被
kill发TERM - 因
set -e中途失败退出 - 正常
exit 0结束
若只在中途写了rm "$tmp",异常退出时临时文件会残留。trap ... EXIT让清理在离开 Shell 前尽量执行一次。
2. 基本语法
trap'echo caught; cleanup'EXIT INTTERM| 部分 | 含义 |
|---|---|
trap | 内置命令 |
'命令' | 触发时由 Shell解析执行的字符串 |
| 信号名 | EXIT、INT、TERM、HUP、ERR等 |
查看信号编号:
trap-l# 或kill-l常见名与含义:
| 信号 | 典型来源 |
|---|---|
| INT | Ctrl+C |
| TERM | kill PID、systemctl stop |
| HUP | 终端挂断、部分服务重载 |
| EXIT | 非信号,Shell退出事件(Bash 等) |
3.EXIT:最常用
#!/usr/bin/env bashset-euopipefailtmpdir=$(mktemp-d)trap'rm -rf "$tmpdir"'EXITecho"work in$tmpdir"# 正常结束或 set -e 失败退出都会 rm -rfEXIT在当前 Shell 退出前运行(包括exit n、脚本末尾、set -e触发退出)。
注意:
- 用
"$tmpdir"引号,在trap 触发时再展开变量(单引号包住 trap 字符串时,变量在执行 trap 时解析)。 trap可多次注册;同信号后注册的会覆盖或追加(Bash 对同信号覆盖前一个 handler)。
trap'echo first'EXITtrap'echo second'EXIT# 最终 EXIT 时通常只跑 second(Bash)4. 临时文件标准模式
tmp=$(mktemp)trap'rm -f "$tmp"'EXIT# 多文件tmps=()cleanup(){rm-f"${tmps[@]}"}trapcleanup EXITtmps+=($(mktemp))函数作 handler(可读性更好):
cleanup(){rm-rf"${tmpdir:-}"}trapcleanup EXIT INTTERMtmpdir=$(mktemp-d)5.INT与TERM:优雅退出
running=1cleanup(){running=0rm-f"$lockfile"echo"interrupted, cleaned">&2}trapcleanup INTTERMEXITwhile((running));dodo_worksleep1done用户Ctrl+C→INT→cleanup(若也注册了EXIT,注意INT 后仍会 EXIT,避免cleanup 跑两次——可合并为同一 handler 并加幂等,见下)。
合并写法:
cleanup(){[["${_cleaned:-}"==1]]&&return_cleaned=1rm-rf"$tmpdir"}trapcleanup EXIT INTTERM6. 忽略与恢复信号
trap''INT# 忽略 Ctrl+C(慎用)trap- INT# 恢复默认 INT 行为长时间计算不想被误中断时偶见trap '' INT;要有其它退出途径。
7.ERR(Bash + 常配合set -e)
set-euopipefailtrap'echo "failed at line $LINENO" >&2'ERRERR:某条命令返回非 0 时触发(set -e生效上下文内,规则有例外,S01-04)。
用于打日志,不替代set -e。
不要在 ERR trap 里再跑会失败的命令而不处理,可能循环。
8.RETURN(Bash,函数返回时)
work(){localtmptmp=$(mktemp)trap'rm -f "$tmp"'RETURN...}函数返回时删函数内临时文件,不影响全局EXIThandler(S08-02 提过)。
9.trap字符串与引号
tmpdir=$(mktemp-d)# 对:触发时展开 $tmpdirtrap'rm -rf "$tmpdir"'EXIT# 错:定义 trap 时就把 $tmpdir 写死进空串(若当时未赋值)trap"rm -rf$tmpdir"EXIT# 定义时展开,易错# 传信号名给 cleanuptrap'cleanup INT'INTcleanup(){echo"got signal">&2rm-rf"$tmpdir"}习惯:handler 用单引号包主体,让$变量在触发时展开。
10. 与set -e、exit的关系
trap'rm -f "$tmp"'EXITfalse# set -e → 退出前仍跑 EXIT trapcleanup(){rm-f"$tmp"exit1# 在 trap 里 exit 要小心}trap里exit可能改变最终退出码;清理函数一般return 0,让外层exit决定码。
11. 读脚本时的常见片段
11.1 锁文件
lock=/tmp/myapp.locktrap'rm -f "$lock"'EXITecho$$>"$lock"11.2 子进程与 trap
trap对当前 Shell 有效;子脚本、( )子 shell需各自注册。bash child.sh里的 trap 不保护父脚本。
11.3 被 source 的库
trap会改当前 Shell;库文件随意trap EXIT可能污染调用方——库应文档化或提供setup_trap可选函数(S08-03)。
12. 注意点小结
| 点 | 说明 |
|---|---|
| EXIT 几乎总要 | 清临时文件、释锁 |
| handler 幂等 | INT + EXIT 可能都触发 |
| 引号 | 触发时展开路径变量 |
| 不要只 trap INT | 仍建议EXIT兜底 |
| 调试 | trap 'echo SIG' DEBUG刷屏,生产慎用 |
读脚本检查清单
- 是否有
mktemp而无trap ... EXIT? - cleanup是否 INT/TERM/EXIT 重复执行需幂等?
- trap 字符串里变量是否会在触发时正确展开?
- source的库是否擅自trap了全局 EXIT?
- ERR trap是否用于日志而非掩盖错误?
练习
判断题
trap 'cmd' EXIT只在exit 0时执行。- Ctrl+C 通常向前台进程组发送 SIGINT。
trap 'rm -f "$f"' EXIT中,若f在 trap 定义后才赋值,触发时仍能删对文件(单引号 trap 字符串)。trap '' INT表示忽略中断。- 子 shell
( trap 'echo x' EXIT; false )退出后,父 shell 的 trap 不受影响。
- 错(任何退出方式,含失败)。
- 对。
- 对(触发时展开
$f)。 - 对。
- 对。
实操题
补全:创建临时文件写入hello,脚本结束前自动删除(含set -e失败路径)。
#!/usr/bin/env bashset-euopipefail# 补全 trap 与 mktempechohello>???cat???参考答案tmp=$(mktemp)trap'rm -f "$tmp"'EXITechohello>"$tmp"cat"$tmp"改错题
tmpdir=$(mktemp-d)trap"rm -rf$tmpdir"EXITcd"$tmpdir"参考tmpdir=$(mktemp-d)trap'rm -rf "$tmpdir"'EXITcd"$tmpdir"双引号 trap 在定义时展开$tmpdir;若写法无误也易在tmpdir未赋值时定义 trap。应用单引号让路径在退出时展开。另:若cd失败,EXIT 仍会删 tmpdir(通常期望)。
下一篇预告
S11-02:《健壮性清单:锁、重试、超时与幂等》— 与trap配合的实战习惯。