news 2026/7/9 15:36:36

Shell脚本精读 · S11-01 | 信号与 `trap`:清理临时文件与优雅退出

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Shell脚本精读 · S11-01 | 信号与 `trap`:清理临时文件与优雅退出

模块: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退出时触发(成功、exitset -e失败均可),适合做清理
  • 临时文件tmp=$(mktemp)trap 'rm -f "$tmp"' EXIT
  • 忽略信号trap '' INT;恢复默认:trap - INT
  • trap处理器里慎用exit,可能打断其它清理。

正文

1. 为什么需要trap

脚本可能:

  • Ctrl+C打断
  • killTERM
  • set -e中途失败退出
  • 正常exit 0结束

若只在中途写了rm "$tmp",异常退出时临时文件会残留
trap ... EXIT让清理在离开 Shell 前尽量执行一次。


2. 基本语法

trap'echo caught; cleanup'EXIT INTTERM
部分含义
trap内置命令
'命令'触发时由 Shell解析执行的字符串
信号名EXITINTTERMHUPERR

查看信号编号:

trap-l# 或kill-l

常见名与含义:

信号典型来源
INTCtrl+C
TERMkill PIDsystemctl 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 -rf

EXIT当前 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.INTTERM:优雅退出

running=1cleanup(){running=0rm-f"$lockfile"echo"interrupted, cleaned">&2}trapcleanup INTTERMEXITwhile((running));dodo_worksleep1done

用户Ctrl+CINTcleanup(若也注册了EXIT,注意INT 后仍会 EXIT,避免cleanup 跑两次——可合并为同一 handler 并加幂等,见下)。

合并写法

cleanup(){[["${_cleaned:-}"==1]]&&return_cleaned=1rm-rf"$tmpdir"}trapcleanup EXIT INTTERM

6. 忽略与恢复信号

trap''INT# 忽略 Ctrl+C(慎用)trap- INT# 恢复默认 INT 行为

长时间计算不想被误中断时偶见trap '' INT;要有其它退出途径。


7.ERR(Bash + 常配合set -e

set-euopipefailtrap'echo "failed at line $LINENO" >&2'ERR

ERR:某条命令返回非 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 -eexit的关系

trap'rm -f "$tmp"'EXITfalse# set -e → 退出前仍跑 EXIT trap
cleanup(){rm-f"$tmp"exit1# 在 trap 里 exit 要小心}

trapexit可能改变最终退出码;清理函数一般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是否用于日志而非掩盖错误?

练习

判断题

  1. trap 'cmd' EXIT只在exit 0时执行。
  2. Ctrl+C 通常向前台进程组发送 SIGINT。
  3. trap 'rm -f "$f"' EXIT中,若f在 trap 定义后才赋值,触发时仍能删对文件(单引号 trap 字符串)。
  4. trap '' INT表示忽略中断。
  5. 子 shell( trap 'echo x' EXIT; false )退出后,父 shell 的 trap 不受影响。
参考答案
  1. 错(任何退出方式,含失败)。
  2. 对。
  3. 对(触发时展开$f)。
  4. 对。
  5. 对。

实操题

补全:创建临时文件写入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配合的实战习惯。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/9 15:32:36

高精度ADC系统设计与优化:ADS131M02与R7FA6M5BH3CFC应用指南

1. 项目背景与核心器件选型解析在工业自动化、医疗设备和测试测量领域,高精度模数转换(ADC)系统的需求持续增长。ADS131M02与R7FA6M5BH3CFC的组合,恰好满足了这类应用对信号采集系统的三大核心要求:高精度、低功耗和灵…

作者头像 李华
网站建设 2026/7/9 15:32:04

MonkeyCode私有化部署实战:Docker+WebSocket+Qwen代码智能平台落地指南

1. 项目概述:MonkeyCode私有化部署到底在解决什么问题?MonkeyCode不是某个具体开源项目的名字,而是对一类“基于大模型能力封装的代码智能辅助平台”的统称——它泛指那些以Qwen系列(尤其是Qwen1.5、Qwen2、Qwen2.5 Code、Qwen3&a…

作者头像 李华
网站建设 2026/7/9 15:31:31

Apache ActiveMQ 5.17.4 漏洞环境一键搭建:Docker Compose 3步复现 CVE-2023-46604

Apache ActiveMQ 5.17.4 漏洞环境一键搭建:Docker Compose 3步复现 CVE-2023-46604消息中间件在现代分布式系统中扮演着关键角色,而Apache ActiveMQ作为其中广泛应用的开源解决方案,其安全性直接关系到企业数据流转的可靠性。2023年曝光的CVE…

作者头像 李华
网站建设 2026/7/9 15:30:27

MCP3428与PIC18LF25K42高精度数据采集系统设计

1. 为什么选择MCP3428与PIC18LF25K42组合在工业现场和实验室环境中,数据采集系统的核心诉求往往集中在三个维度:精度、功耗和扩展性。MCP3428作为一款18位Δ-Σ ADC芯片,其内置的2.048V基准电压和可编程增益放大器(PGA)能够直接处理毫伏级信号…

作者头像 李华
网站建设 2026/7/9 15:28:14

ESP32 HUB75矩阵屏长文本显示:5分钟实现流畅滚动效果

ESP32 HUB75矩阵屏长文本显示:5分钟实现流畅滚动效果 【免费下载链接】ESP32-HUB75-MatrixPanel-DMA An Adafruit GFX Compatible Library for the ESP32, ESP32-S2, ESP32-S3 to drive HUB75 LED matrix panels using DMA for high refresh rates. Supports panel …

作者头像 李华
网站建设 2026/7/9 15:27:51

C++实现微积分算法:从数值微分到自适应积分的工程实践

1. 项目概述:当C遇上微积分作为一名在工业软件和科学计算领域摸爬滚打了十多年的老码农,我经常被问到:“学C到底有什么用?除了做游戏和操作系统,还能干啥?” 每当这时,我总会提起微积分。这听起…

作者头像 李华