--- #领域/Linux #复盘/2 ## 一句话描述 [____脚本错误处理____] --- ## 核心规范 >空想不如行动,积累胜于苛求。 >实践 > 沉淀 > 完美主义 实践不是盲目行动,而是带着“小目标、可验证“的方向试错,实践后必须沉淀(比如记录问题、总结规律),否则就是低水平重复。 实践大于沉淀,沉淀大于完美;完美是沉淀的终局方向,沉淀是实践的复盘产物;分域施策,避坑落地,始于行动,终于迭代。 --- ## 三省沉淀法 - 达成了[___脚本处理异常错误_____]目标 - 遇到了[__目前脚本均为应用该处理______]问题 - 下次改进[_逐步引进错误处理机制_______] ## 个人理解 [__if、tray的判断、捕获,只是bash语法用法不同,道理是相通的______] ## 实践计划 #状态/待实践 1. [__编写错误处理模板______] 2. [__在脚本中引入错误处理模板______] 3. [________] --- ## 核心定义 trap 用于捕获[___系统信号_/ 脚本状态____],暂停当前程序,并触发命令,再继续执行程序 可做异常处理、资源清理、流程控制 ### 基础语法 ```bash # 绑定信号 + 执行命令 trap "要执行的命令" 信号名/信号编号 信号名/信号编号 # 可绑定多个 # 忽略指定信号 trap "" 信号名/信号编号 EXIT # EXIT 必用信号 # 重置信号为默认行为 trap - 信号名/信号编号 ``` ### 常用信号 | 信号名 | 信号编号 | 触发场景 | 核心用途 | | ------- | ---- | ------------------- | ------------ | | SIGINT | 2 | 按 Ctrl+C 中断进程 | 捕获用户手动中断,做清理 | | SIGTERM | 15 | kill 命令默认发送的终止信号 | 优雅终止脚本,释放资源 | | EXIT | 无编号 | 脚本正常 / 异常退出时触发 | 脚本收尾,清理临时文件 | | SIGHUP | 1 | 终端关闭 / 连接断开 | 处理后台脚本的终端断开 | | SIGQUIT | 3 | 按 Ctrl+\ 退出并生成 core | 捕获强制退出,做日志记录 | ### 示例 #### ✅ 示例:脚本退出时自动清理 脚本运行生成临时文件,无论正常 / 异常退出,都要删除,避免垃圾文件残留 ```bash #!/bin/bash # 定义临时文件路径 TMP_FILE="/tmp/test_trap.tmp" # 绑定EXIT信号,退出时删除临时文件 trap "rm -f $TMP_FILE; echo '临时文件已清理,脚本退出'" EXIT # 脚本主逻辑:创建临时文件并写入内容 echo "脚本运行中,生成临时文件" > $TMP_FILE cat $TMP_FILE # 模拟脚本正常结束 echo "脚本主逻辑执行完毕" ``` #### ✅ 示例:捕获用户中断(Ctrl+C),做优雅处理 用户手动中断脚本时,不直接退出,先提示并完成收尾。 ```bash #!/bin/bash # 绑定SIGINT信号(Ctrl+C),捕获后执行自定义逻辑 trap "echo -e '\n用户手动中断,正在保存数据...'; exit 1" SIGINT # 脚本主逻辑:模拟耗时任务 echo "脚本正在执行耗时任务,按Ctrl+C可中断" for i in {1..5}; do echo "任务进度:$i/5" sleep 1 done echo "任务执行完成" ``` #### ✅ 示例:忽略指定信号(防止脚本被误杀) 后台运行的脚本,忽略 Ctrl+C 中断,避免用户误操作终止。 ```bash #!/bin/bash # 忽略SIGINT信号(Ctrl+C) trap "" SIGINT echo "脚本已忽略Ctrl+C,按Ctrl+\\可强制退出" # 模拟后台循环任务 while true; do echo "脚本运行中..." sleep 2 done ``` #### ✅ 示例:多信号绑定同一处理逻辑 SIGINT、SIGTERM 触发时,执行相同的清理 + 退出逻辑。 ```bash #!/bin/bash TMP_DIR="/tmp/trap_test" mkdir -p $TMP_DIR # 绑定多个信号,执行统一清理 trap "rm -rf $TMP_DIR; echo '清理临时目录,脚本退出'; exit" SIGINT SIGTERM EXIT echo "脚本运行,临时目录:$TMP_DIR" sleep 10 ``` #### ✅ 示例:`$?`捕获最近命令错误码(局部捕获) 这里是关闭 set -euo pipefail,使用手动处理异常 ```bash #!/bin/bash # set -euo pipefail ls /不存在的目录 err_code=$?  # 捕获错误码 if [ $err_code -ne 0 ]; then     echo "命令执行失败,错误码:$err_code"     exit $err_code  # 主动退出并返回错误码 fi ``` #### ✅ 示例:trap 捕获全局错误 详见:[[20260204-备忘-linux-trap]] ```bash #!/bin/bash set -euo pipefail # 错误处理函数:定位出错行+记录信息 error_handler() { local line=$1 local err_code=$? echo "$(date +'%Y-%m-%d %H:%M:%S') - 第$line行失败,错误码:$err_code" >> /var/log/script_err.log exit $err_code } # 捕获ERR(命令失败)、EXIT(脚本退出)信号 trap 'error_handler $LINENO' ERR EXIT ls /不存在的目录 # 触发ERR信号,执行error_handler ``` ```bash #!/bin/bash set -euo pipefail # 清理函数:删除临时文件、释放资源 cleanup() { echo "执行清理操作..." rm -rf /临时目录 # 删除临时目录 # 可选:关闭数据库连接、释放锁等 } # 脚本退出时(无论成功/失败)执行清理 trap cleanup EXIT # 模拟关键操作失败 mkdir /临时目录 ls /不存在的目录 # 触发错误,退出前执行cleanup ``` #### ✅ 示例:非关键命令允许失败 详见:[[Linux-set处理未定义和错误]] ```bash #!/bin/bash set -euo pipefail # 临时关闭-e,允许rm失败(比如文件不存在) set +e rm /临时文件.txt # 失败也不退出 set -e # 恢复严格模式 # 关键命令:失败则退出 cp /源文件 /目标文件 ``` #### ✅ 示例:临时错误重试 ```bash #!/bin/bash set -euo pipefail # 重试函数:参数1=重试次数,参数2=待执行命令 retry() { local retries=$1 local cmd=$2 local count=0 while [ $count -lt $retries ]; do $cmd && return 0 # 执行成功则返回 count=$((count+1)) echo "重试第$count次..." sleep 1 # 重试间隔 done echo "重试$retries次后仍失败" return 1 } # 重试下载文件(网络可能临时失败) retry 3 "curl -O https://example.com/test.txt" ``` ### 避坑点 ⚠️ 避坑点1: 解决方案: ⚠️ 避坑点1: 核心问题: 解决方案:✅