You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash备份脚本中handle_exit退出码恒为0的原因及区分方法

PostgreSQL备份脚本错误处理优化方案

1. 修复handle_exit无法区分执行状态的问题

核心问题是handle_error执行后会重置$?的值,导致handle_exit拿到的是handle_error的退出码而非原始错误码。解决方法是在handle_error中先捕获原始错误码,再作为参数传递给handle_exit:

# 错误处理函数:捕获原始错误码并传递给退出处理函数
handle_error() {
    local original_exit_code=$?
    local error_details="备份流程出错,错误码:${original_exit_code}\n错误上下文:$(history 1 | awk '{print substr($0, index($0,$2))}')"
    
    # 调用退出处理函数,传入原始错误码
    handle_exit "${original_exit_code}" "${error_details}"
}

# 退出处理函数:根据传入的错误码执行不同逻辑
handle_exit() {
    local exit_code=$1
    local msg=$2

    if [ "${exit_code}" -ne 0 ]; then
        # 发送失败通知邮件
        echo -e "${msg}" | mail -s "PostgreSQL备份失败" admin@yourdomain.com
    else
        # 发送成功通知邮件
        echo "PostgreSQL备份已完成并成功上传至S3" | mail -s "PostgreSQL备份成功" admin@yourdomain.com
    fi

    exit "${exit_code}"
}

# 脚本开头设置陷阱,捕获所有错误触发handle_error
trap 'handle_error' ERR

2. handle_error中邮件发送失败的处理

如果邮件发送命令(如mail)执行失败,可通过以下方式避免错误信息丢失:

  • 写入本地日志文件留存记录
  • 增加重试机制提升送达率

示例实现:

send_mail() {
    local subject=$1
    local content=$2
    local retry_count=2
    local send_result=1

    # 重试发送邮件
    while [ "${retry_count}" -gt 0 ] && [ "${send_result}" -ne 0 ]; do
        echo -e "${content}" | mail -s "${subject}" admin@yourdomain.com
        send_result=$?
        retry_count=$((retry_count - 1))
        [ "${retry_count}" -gt 0 ] && sleep 5
    done

    # 若最终发送失败,写入本地日志
    if [ "${send_result}" -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') 邮件发送失败,主题:${subject}\n内容:${content}\n" >> /var/log/pg_backup_mail_errors.log
    fi
}

# 修改handle_exit中的邮件发送逻辑,调用上述函数
handle_exit() {
    local exit_code=$1
    local msg=$2

    if [ "${exit_code}" -ne 0 ]; then
        send_mail "PostgreSQL备份失败" "${msg}"
    else
        send_mail "PostgreSQL备份成功" "PostgreSQL备份已完成并成功上传至S3"
    fi

    exit "${exit_code}"
}

3. 无需临时文件获取错误信息的方案

直接在执行关键命令时捕获stderr到变量,无需写入临时文件:

方案1:捕获单命令的错误输出

# 执行pg_dumpall并捕获所有输出(stdout+stderr)
backup_result=$(pg_dumpall -U postgres 2>&1)
backup_exit_code=$?

if [ "${backup_exit_code}" -ne 0 ]; then
    handle_error_custom "${backup_exit_code}" "pg_dumpall执行失败:${backup_result}"
else
    # 执行S3上传并捕获错误
    upload_result=$(aws s3 cp "./pg_backup_$(date +%Y%m%d).sql" s3://your-backup-bucket/ 2>&1)
    upload_exit_code=$?
    if [ "${upload_exit_code}" -ne 0 ]; then
        handle_error_custom "${upload_exit_code}" "S3上传失败:${upload_result}"
    else
        handle_exit 0 ""
    fi
fi

方案2:结合陷阱与全局变量

declare -g global_error_msg=""

# 自定义错误处理函数,接收错误码和错误信息
handle_error_custom() {
    local exit_code=$1
    local error_msg=$2
    global_error_msg="${error_msg}"
    handle_exit "${exit_code}" "${global_error_msg}"
}

# 执行命令时直接捕获错误并触发处理
pg_dumpall -U postgres || handle_error_custom $? "pg_dumpall执行失败:$(pg_dumpall -U postgres 2>&1)"
aws s3 cp "./pg_backup_$(date +%Y%m%d).sql" s3://your-backup-bucket/ || handle_error_custom $? "S3上传失败:$(aws s3 cp "./pg_backup_$(date +%Y%m%d).sql" s3://your-backup-bucket/ 2>&1)"

内容的提问来源于stack exchange,提问作者PirateApp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 22:47:03