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
相关产品推荐
相关产品推荐

