258 lines
6.1 KiB
Markdown
258 lines
6.1 KiB
Markdown
|
||
---
|
||
#领域/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:
|
||
核心问题:
|
||
解决方案:✅ |