feat: 代码标准化和文件重命名
## 新增功能 - 创建统一的公共函数库 (common/logging.sh, common/error_handler.sh) - 添加功能演示脚本 (common/demo_usage.sh) - 完善的使用文档 (common/README.md) ## 代码重构 - 重构所有脚本使用统一的公共库 - 为所有函数添加完整的文档注释 - 统一代码格式(4空格缩进、严格模式) - 标准化错误处理和日志输出 ## 文件重命名 - gcp/create_ai_project.sh → gcp/create_ai_projects.sh (单复数统一) - gcp/delete_all_project.sh → gcp/delete_all_projects.sh (单复数统一) - linux/install_ohmyzsh.sh → linux/install_oh_my_zsh.sh (专有名词规范) - linux/create_raid0_with_ext4.sh → linux/create_raid0_array.sh (简化命名) - common/example.sh → common/demo_usage.sh (更具描述性) ## 技术改进 - 使用 readonly 声明常量 - 启用 set -euo pipefail 严格模式 - 统一的 ANSI 颜色日志输出 - 完善的命令重试机制 - 栈追踪支持
This commit is contained in:
300
common/error_handler.sh
Normal file
300
common/error_handler.sh
Normal file
@@ -0,0 +1,300 @@
|
||||
#!/bin/bash
|
||||
# ============================================================================
|
||||
# 文件名: error_handler.sh
|
||||
# 描述: 统一的错误处理机制
|
||||
# 作者: Cloud Tools Project
|
||||
# 版本: 1.0.0
|
||||
# 依赖: logging.sh
|
||||
# 使用方法: source common/error_handler.sh
|
||||
# ============================================================================
|
||||
|
||||
# 确保加载日志库
|
||||
if ! declare -f log_error >/dev/null 2>&1; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=./logging.sh
|
||||
source "${SCRIPT_DIR}/logging.sh"
|
||||
fi
|
||||
|
||||
# 错误处理配置
|
||||
ERROR_EXIT_ON_FAIL=${ERROR_EXIT_ON_FAIL:-true}
|
||||
ERROR_STACK_TRACE=${ERROR_STACK_TRACE:-false}
|
||||
|
||||
#
|
||||
# 内部: 获取调用栈信息
|
||||
# 返回: 格式化的调用栈字符串
|
||||
#
|
||||
_error_get_stack_trace() {
|
||||
local frame=0
|
||||
local line
|
||||
local func
|
||||
local src
|
||||
|
||||
echo "调用栈:"
|
||||
while caller $frame; do
|
||||
((frame++))
|
||||
done | while read -r line func src; do
|
||||
echo " at $func ($src:$line)"
|
||||
done
|
||||
}
|
||||
|
||||
#
|
||||
# 检查命令是否存在
|
||||
# 参数: $1 - 命令名称
|
||||
# 返回: 0=存在, 1=不存在
|
||||
# 示例: check_command "git" || error_exit "git 未安装"
|
||||
#
|
||||
check_command() {
|
||||
local cmd="$1"
|
||||
|
||||
if ! command -v "$cmd" &>/dev/null; then
|
||||
log_error "命令不存在: $cmd"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# 检查文件是否存在
|
||||
# 参数: $1 - 文件路径
|
||||
# 返回: 0=存在, 1=不存在
|
||||
# 示例: check_file "/path/to/file" || error_exit "文件不存在"
|
||||
#
|
||||
check_file() {
|
||||
local file="$1"
|
||||
|
||||
if [[ ! -f "$file" ]]; then
|
||||
log_error "文件不存在: $file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# 检查目录是否存在
|
||||
# 参数: $1 - 目录路径
|
||||
# 返回: 0=存在, 1=不存在
|
||||
# 示例: check_directory "/path/to/dir" || error_exit "目录不存在"
|
||||
#
|
||||
check_directory() {
|
||||
local dir="$1"
|
||||
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
log_error "目录不存在: $dir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# 检查变量是否为空
|
||||
# 参数:
|
||||
# $1 - 变量值
|
||||
# $2 - 变量名称 (可选,用于错误消息)
|
||||
# 返回: 0=非空, 1=为空
|
||||
# 示例: check_not_empty "$VAR" "VAR" || error_exit "变量不能为空"
|
||||
#
|
||||
check_not_empty() {
|
||||
local value="$1"
|
||||
local var_name="${2:-变量}"
|
||||
|
||||
if [[ -z "$value" ]]; then
|
||||
log_error "${var_name} 不能为空"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# 检查是否以 root 权限运行
|
||||
# 返回: 0=是root, 1=不是root
|
||||
# 示例: check_root || error_exit "此脚本需要 root 权限"
|
||||
#
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "此脚本需要 root 权限运行"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# 检查命令返回值
|
||||
# 参数:
|
||||
# $1 - 命令返回值 ($?)
|
||||
# $2 - 错误消息 (可选)
|
||||
# 返回: 传入的返回值
|
||||
# 示例: some_command; check_return $? "命令执行失败"
|
||||
#
|
||||
check_return() {
|
||||
local ret=$1
|
||||
local msg="${2:-命令执行失败}"
|
||||
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
log_error "$msg (退出码: $ret)"
|
||||
|
||||
if [[ "$ERROR_STACK_TRACE" == "true" ]]; then
|
||||
_error_get_stack_trace >&2
|
||||
fi
|
||||
|
||||
if [[ "$ERROR_EXIT_ON_FAIL" == "true" ]]; then
|
||||
exit "$ret"
|
||||
fi
|
||||
fi
|
||||
|
||||
return "$ret"
|
||||
}
|
||||
|
||||
#
|
||||
# 错误退出
|
||||
# 参数:
|
||||
# $1 - 错误消息
|
||||
# $2 - 退出码 (可选,默认: 1)
|
||||
# 示例: error_exit "配置文件不存在" 2
|
||||
#
|
||||
error_exit() {
|
||||
local msg="$1"
|
||||
local exit_code="${2:-1}"
|
||||
|
||||
log_error "$msg"
|
||||
|
||||
if [[ "$ERROR_STACK_TRACE" == "true" ]]; then
|
||||
_error_get_stack_trace >&2
|
||||
fi
|
||||
|
||||
exit "$exit_code"
|
||||
}
|
||||
|
||||
#
|
||||
# 执行命令并检查结果
|
||||
# 参数:
|
||||
# $1 - 错误消息前缀
|
||||
# $@ - 要执行的命令和参数
|
||||
# 返回: 命令的返回值
|
||||
# 示例: run_command "安装失败" apt-get install -y package
|
||||
#
|
||||
run_command() {
|
||||
local error_msg="$1"
|
||||
shift
|
||||
|
||||
log_debug "执行命令: $*"
|
||||
|
||||
if ! "$@"; then
|
||||
local ret=$?
|
||||
log_error "${error_msg}: $*"
|
||||
|
||||
if [[ "$ERROR_EXIT_ON_FAIL" == "true" ]]; then
|
||||
exit "$ret"
|
||||
fi
|
||||
|
||||
return "$ret"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#
|
||||
# 带重试的命令执行
|
||||
# 参数:
|
||||
# $1 - 最大重试次数
|
||||
# $2 - 重试间隔 (秒)
|
||||
# $3 - 错误消息前缀
|
||||
# $@ - 要执行的命令和参数
|
||||
# 返回: 命令的返回值
|
||||
# 示例: retry_command 3 5 "连接失败" curl -f https://example.com
|
||||
#
|
||||
retry_command() {
|
||||
local max_retries=$1
|
||||
local retry_delay=$2
|
||||
local error_msg="$3"
|
||||
shift 3
|
||||
|
||||
local attempt=1
|
||||
local ret
|
||||
|
||||
while [[ $attempt -le $max_retries ]]; do
|
||||
log_debug "尝试执行 (第 $attempt/$max_retries 次): $*"
|
||||
|
||||
if "$@"; then
|
||||
log_debug "命令执行成功"
|
||||
return 0
|
||||
fi
|
||||
|
||||
ret=$?
|
||||
|
||||
if [[ $attempt -lt $max_retries ]]; then
|
||||
log_warning "${error_msg} (第 $attempt 次失败,将在 ${retry_delay}秒后重试)"
|
||||
sleep "$retry_delay"
|
||||
else
|
||||
log_error "${error_msg} (已重试 $max_retries 次)"
|
||||
fi
|
||||
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
if [[ "$ERROR_EXIT_ON_FAIL" == "true" ]]; then
|
||||
exit "$ret"
|
||||
fi
|
||||
|
||||
return "$ret"
|
||||
}
|
||||
|
||||
#
|
||||
# 启用错误时退出
|
||||
# 示例: enable_exit_on_error
|
||||
#
|
||||
enable_exit_on_error() {
|
||||
ERROR_EXIT_ON_FAIL=true
|
||||
set -e
|
||||
set -o pipefail
|
||||
}
|
||||
|
||||
#
|
||||
# 禁用错误时退出
|
||||
# 示例: disable_exit_on_error
|
||||
#
|
||||
disable_exit_on_error() {
|
||||
ERROR_EXIT_ON_FAIL=false
|
||||
set +e
|
||||
set +o pipefail
|
||||
}
|
||||
|
||||
#
|
||||
# 启用调用栈跟踪
|
||||
# 示例: enable_stack_trace
|
||||
#
|
||||
enable_stack_trace() {
|
||||
ERROR_STACK_TRACE=true
|
||||
}
|
||||
|
||||
#
|
||||
# 禁用调用栈跟踪
|
||||
# 示例: disable_stack_trace
|
||||
#
|
||||
disable_stack_trace() {
|
||||
ERROR_STACK_TRACE=false
|
||||
}
|
||||
|
||||
# 设置 ERR 陷阱(可选)
|
||||
# trap '_error_handler $? $LINENO' ERR
|
||||
|
||||
#
|
||||
# 内部: ERR 陷阱处理函数
|
||||
# 参数:
|
||||
# $1 - 错误码
|
||||
# $2 - 行号
|
||||
#
|
||||
_error_handler() {
|
||||
local exit_code=$1
|
||||
local line_number=$2
|
||||
|
||||
log_error "脚本在第 $line_number 行发生错误 (退出码: $exit_code)"
|
||||
|
||||
if [[ "$ERROR_STACK_TRACE" == "true" ]]; then
|
||||
_error_get_stack_trace >&2
|
||||
fi
|
||||
}
|
||||
Reference in New Issue
Block a user