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

6.1 KiB
Raw Permalink Blame History


#领域/Linux

#复盘/2

一句话描述

[脚本错误处理]


核心规范

空想不如行动,积累胜于苛求。 实践 > 沉淀 > 完美主义

实践不是盲目行动,而是带着“小目标、可验证“的方向试错,实践后必须沉淀(比如记录问题、总结规律),否则就是低水平重复。

实践大于沉淀,沉淀大于完美;完美是沉淀的终局方向,沉淀是实践的复盘产物;分域施策,避坑落地,始于行动,终于迭代。


三省沉淀法

  • 达成了[脚本处理异常错误__]目标
  • 遇到了[目前脚本均为应用该处理____]问题
  • 下次改进[逐步引进错误处理机制______]

个人理解

[if、tray的判断、捕获只是bash语法用法不同道理是相通的____]

实践计划

#状态/待实践

  1. [编写错误处理模板____]
  2. [在脚本中引入错误处理模板____]
  3. [________]

核心定义

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 捕获全局错误

详见:20260204-备忘-linux-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

示例:非关键命令允许失败

详见:Linux-set处理未定义和错误

#!/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 核心问题: 解决方案: