juechafun/05-原子化笔记本/Linux-trap脚本错误.md

258 lines
6.1 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
#领域/Linux
#复盘/0
## 一句话描述
[____脚本错误处理____]
---
## 核心规范
>空想不如行动,积累胜于苛求。
>实践 > 沉淀 > 完美主义
实践不是盲目行动,而是带着“小目标、可验证“的方向试错,实践后必须沉淀(比如记录问题、总结规律),否则就是低水平重复。
实践大于沉淀,沉淀大于完美;完美是沉淀的终局方向,沉淀是实践的复盘产物;分域施策,避坑落地,始于行动,终于迭代。
---
## 三省沉淀法
- 达成了[___脚本处理异常错误_____]目标
- 遇到了[__目前脚本均为应用该处理______]问题
- 下次改进[_逐步引进错误处理机制_______]
## 个人理解
[__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
核心问题:
解决方案:✅