6.1 KiB
6.1 KiB
#领域/Linux
#复盘/2
一句话描述
[脚本错误处理]
核心规范
空想不如行动,积累胜于苛求。 实践 > 沉淀 > 完美主义
实践不是盲目行动,而是带着“小目标、可验证“的方向试错,实践后必须沉淀(比如记录问题、总结规律),否则就是低水平重复。
实践大于沉淀,沉淀大于完美;完美是沉淀的终局方向,沉淀是实践的复盘产物;分域施策,避坑落地,始于行动,终于迭代。
三省沉淀法
- 达成了[脚本处理异常错误__]目标
- 遇到了[目前脚本均为应用该处理____]问题
- 下次改进[逐步引进错误处理机制______]
个人理解
[if、tray的判断、捕获,只是bash语法用法不同,道理是相通的____]
实践计划
#状态/待实践
- [编写错误处理模板____]
- [在脚本中引入错误处理模板____]
- [________]
核心定义
trap 用于捕获[系统信号/ 脚本状态__],暂停当前程序,并触发命令,再继续执行程序 可做异常处理、资源清理、流程控制
基础语法
# 绑定信号 + 执行命令
trap "要执行的命令" 信号名/信号编号 信号名/信号编号 # 可绑定多个
# 忽略指定信号
trap "" 信号名/信号编号 EXIT # EXIT 必用信号
# 重置信号为默认行为
trap - 信号名/信号编号
常用信号
| 信号名 | 信号编号 | 触发场景 | 核心用途 |
|---|---|---|---|
| SIGINT | 2 | 按 Ctrl+C 中断进程 | 捕获用户手动中断,做清理 |
| SIGTERM | 15 | kill 命令默认发送的终止信号 | 优雅终止脚本,释放资源 |
| EXIT | 无编号 | 脚本正常 / 异常退出时触发 | 脚本收尾,清理临时文件 |
| SIGHUP | 1 | 终端关闭 / 连接断开 | 处理后台脚本的终端断开 |
| SIGQUIT | 3 | 按 Ctrl+\ 退出并生成 core | 捕获强制退出,做日志记录 |
示例
✅ 示例:脚本退出时自动清理
脚本运行生成临时文件,无论正常 / 异常退出,都要删除,避免垃圾文件残留
#!/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),做优雅处理
用户手动中断脚本时,不直接退出,先提示并完成收尾。
#!/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 中断,避免用户误操作终止。
#!/bin/bash
# 忽略SIGINT信号(Ctrl+C)
trap "" SIGINT
echo "脚本已忽略Ctrl+C,按Ctrl+\\可强制退出"
# 模拟后台循环任务
while true; do
echo "脚本运行中..."
sleep 2
done
✅ 示例:多信号绑定同一处理逻辑
SIGINT、SIGTERM 触发时,执行相同的清理 + 退出逻辑。
#!/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,使用手动处理异常
#!/bin/bash
# set -euo pipefail
ls /不存在的目录
err_code=$? # 捕获错误码
if [ $err_code -ne 0 ]; then
echo "命令执行失败,错误码:$err_code"
exit $err_code # 主动退出并返回错误码
fi
✅ 示例:trap 捕获全局错误
#!/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
#!/bin/bash
set -euo pipefail
# 清理函数:删除临时文件、释放资源
cleanup() {
echo "执行清理操作..."
rm -rf /临时目录 # 删除临时目录
# 可选:关闭数据库连接、释放锁等
}
# 脚本退出时(无论成功/失败)执行清理
trap cleanup EXIT
# 模拟关键操作失败
mkdir /临时目录
ls /不存在的目录 # 触发错误,退出前执行cleanup
✅ 示例:非关键命令允许失败
#!/bin/bash
set -euo pipefail
# 临时关闭-e,允许rm失败(比如文件不存在)
set +e
rm /临时文件.txt # 失败也不退出
set -e # 恢复严格模式
# 关键命令:失败则退出
cp /源文件 /目标文件
✅ 示例:临时错误重试
#!/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: 核心问题: 解决方案:✅