本文目录导读:

在Shell脚本中实现条件回滚策略,通常用于处理复杂的操作序列,确保在某个步骤失败时能够安全地恢复到初始状态,以下是几种常见的实现方法:
基本回滚模式
#!/bin/bash
set -e # 遇到错误立即退出
# 记录已执行的操作
declare -a executed_steps=()
declare -a rollback_commands=()
# 注册回滚命令
register_rollback() {
rollback_commands+=("$1")
}
# 执行回滚
rollback() {
echo "=== 开始回滚 ==="
for (( i=${#rollback_commands[@]}-1; i>=0; i-- )); do
echo "回滚步骤 $i: ${rollback_commands[$i]}"
eval "${rollback_commands[$i]}" || echo "回滚步骤 $i 失败: ${rollback_commands[$i]}"
done
echo "=== 回滚完成 ==="
}
# 主流程
main() {
# 步骤1: 创建文件
echo "步骤1: 创建临时文件"
touch /tmp/test_1.txt
register_rollback "rm -f /tmp/test_1.txt"
# 步骤2: 修改配置文件
echo "步骤2: 修改配置"
cp /etc/config /etc/config.backup
register_rollback "cp /etc/config.backup /etc/config"
# 步骤3: 执行可能失败的操作
echo "步骤3: 执行关键操作"
if ! some_command; then
echo "步骤3 失败,开始回滚"
rollback
exit 1
fi
echo "所有步骤成功完成"
}
# 捕获退出信号
trap rollback EXIT
main
使用函数实现回滚
#!/bin/bash
# 回滚堆栈
ROLLBACK_STACK=()
# 压入回滚函数
push_rollback() {
ROLLBACK_STACK+=("$1")
}
# 执行所有回滚
execute_rollback() {
local total=${#ROLLBACK_STACK[@]}
echo "执行 $total 个回滚操作"
for (( i=total-1; i>=0; i-- )); do
echo "执行回滚 #$i"
eval "${ROLLBACK_STACK[$i]}"
done
ROLLBACK_STACK=() # 清空堆栈
}
# 示例操作函数
create_file() {
local file=$1
echo "创建文件: $file"
touch "$file" || return 1
# 注册回滚
local rollback_cmd="rm -f $file"
push_rollback "$rollback_cmd"
}
copy_config() {
local src=$1 dst=$2
echo "复制配置: $src -> $dst"
cp "$src" "$dst" || return 1
# 注册回滚
local rollback_cmd="cp $dst $src"
push_rollback "$rollback_cmd"
}
start_service() {
local service=$1
echo "启动服务: $service"
systemctl start "$service" || return 1
# 注册回滚
local rollback_cmd="systemctl stop $service"
push_rollback "$rollback_cmd"
}
# 主函数
main() {
# 执行操作序列
create_file "/tmp/backup.tar.gz" || return 1
copy_config "/etc/nginx/nginx.conf" "/tmp/nginx.conf.backup" || return 1
start_service "nginx" || return 1
echo "所有操作成功完成"
return 0
}
# 执行并处理错误
if ! main; then
echo "操作失败,执行回滚"
execute_rollback
exit 1
fi
带状态检查的回滚
#!/bin/bash
# 状态管理
STATE_FILE="/tmp/deploy_state.txt"
ROLLBACK_FILE="/tmp/rollback_commands.txt"
init_state() {
> "$STATE_FILE"
> "$ROLLBACK_FILE"
}
record_step() {
local step=$1
echo "$step" >> "$STATE_FILE"
}
record_rollback() {
local command=$1
echo "$command" >> "$ROLLBACK_FILE"
}
execute_rollback() {
echo "=== 执行条件回滚 ==="
# 读取状态文件
local states=()
while IFS= read -r line; do
states+=("$line")
done < "$ROLLBACK_FILE"
# 逆序执行回滚
for (( i=${#states[@]}-1; i>=0; i-- )); do
local cmd="${states[$i]}"
echo "执行回滚命令: $cmd"
eval "$cmd" || {
echo "回滚命令失败: $cmd"
# 继续执行其他回滚
}
done
# 清理状态文件
rm -f "$STATE_FILE" "$ROLLBACK_FILE"
}
# 带条件的回滚
conditional_rollback() {
local condition=$1
local rollback_cmd=$2
if [ "$condition" = "true" ]; then
eval "$rollback_cmd"
echo "条件回滚执行: $rollback_cmd"
fi
}
# 示例使用
main() {
init_state
# 步骤1: 创建目录
echo "步骤1: 创建应用目录"
mkdir -p /var/www/new_app
record_step "create_dir"
record_rollback "rm -rf /var/www/new_app"
# 步骤2: 复制文件
echo "步骤2: 复制应用文件"
cp -r /tmp/app/* /var/www/new_app/
record_step "copy_files"
record_rollback "rm -rf /var/www/new_app"
# 步骤3: 设置权限
echo "步骤3: 设置文件权限"
chmod -R 755 /var/www/new_app
record_step "set_permissions"
# 检查磁盘空间
available_space=$(df /var/www/new_app | awk 'NR==2 {print $4}')
if [ "$available_space" -lt 1000000 ]; then
echo "磁盘空间不足 (可用: $available_space KB)"
execute_rollback
exit 1
fi
echo "所有步骤完成"
}
# 执行主函数
main
事务型回滚模式
#!/bin/bash
# 事务管理器
TRANSACTION_LOG="/tmp/transaction.log"
ROLLBACK_LOG="/tmp/rollback.log"
begin_transaction() {
echo "开始事务: $(date)" > "$TRANSACTION_LOG"
echo "" > "$ROLLBACK_LOG"
}
commit_transaction() {
echo "提交事务: $(date)" >> "$TRANSACTION_LOG"
rm -f "$TRANSACTION_LOG" "$ROLLBACK_LOG"
}
rollback_transaction() {
echo "回滚事务: $(date)" >> "$TRANSACTION_LOG"
if [ -f "$ROLLBACK_LOG" ]; then
echo "开始执行回滚..."
while IFS= read -r line; do
echo "回滚: $line"
eval "$line" || echo "回滚失败: $line"
done < "$ROLLBACK_LOG"
fi
# 清理
rm -f "$TRANSACTION_LOG" "$ROLLBACK_LOG"
}
add_operation() {
local description=$1
local action=$2
local rollback=$3
echo "执行: $description"
eval "$action" || {
echo "操作失败: $description"
rollback_transaction
return 1
}
# 记录回滚命令
echo "$rollback" >> "$ROLLBACK_LOG"
}
# 示例
main() {
begin_transaction
# 添加操作
add_operation "创建备份" \
"cp /etc/config /etc/config.bak" \
"cp /etc/config.bak /etc/config" || exit 1
add_operation "修改配置" \
"echo 'new_config' > /etc/config" \
"cp /etc/config.bak /etc/config" || exit 1
add_operation "重启服务" \
"systemctl restart nginx" \
"systemctl restart nginx_old" || exit 1
# 所有操作成功
commit_transaction
echo "所有操作成功完成"
}
main
实用的部署回滚脚本
#!/bin/bash
# 定义版本和回滚点
DEPLOY_DIR="/var/www/app"
BACKUP_DIR="/var/backups/app"
VERSION_FILE="$DEPLOY_DIR/version.txt"
# 创建备份点
create_checkpoint() {
local timestamp=$(date +%Y%m%d_%H%M%S)
local checkpoint_dir="$BACKUP_DIR/checkpoint_$timestamp"
echo "创建检查点: $checkpoint_dir"
mkdir -p "$checkpoint_dir"
cp -r "$DEPLOY_DIR"/* "$checkpoint_dir/"
echo "$checkpoint_dir" > /tmp/current_checkpoint
echo "$timestamp" > "$VERSION_FILE"
}
# 回滚到检查点
rollback_to_checkpoint() {
local checkpoint=$(cat /tmp/current_checkpoint 2>/dev/null)
if [ -z "$checkpoint" ] || [ ! -d "$checkpoint" ]; then
echo "错误: 没有可用的检查点"
return 1
fi
echo "回滚到: $checkpoint"
# 停止服务
systemctl stop nginx 2>/dev/null
# 回滚文件
rm -rf "$DEPLOY_DIR"/*
cp -r "$checkpoint"/* "$DEPLOY_DIR/"
# 启动服务
systemctl start nginx 2>/dev/null
echo "回滚完成"
}
# 带条件的部署
deploy() {
local version=$1
echo "开始部署版本: $version"
# 条件检查
if [ ! -f "/tmp/app_$version.tar.gz" ]; then
echo "错误: 版本包不存在"
return 1
fi
# 创建备份点
create_checkpoint
# 解压新版本
tar -xzf "/tmp/app_$version.tar.gz" -C "$DEPLOY_DIR" || {
echo "解压失败,执行回滚"
rollback_to_checkpoint
return 1
}
# 检查配置文件
if [ ! -f "$DEPLOY_DIR/config/app.conf" ]; then
echo "配置文件缺失,回滚"
rollback_to_checkpoint
return 1
fi
# 重启服务
systemctl restart nginx || {
echo "服务重启失败,回滚"
rollback_to_checkpoint
return 1
}
echo "部署成功"
}
# 主菜单
case "${1:-help}" in
deploy)
deploy "$2"
;;
rollback)
rollback_to_checkpoint
;;
check)
echo "当前版本: $(cat $VERSION_FILE 2>/dev/null || echo 'unknown')"
;;
*)
echo "用法: $0 {deploy|rollback|check} [version]"
;;
esac
关键原则
- 原子性: 确保操作要么全部成功,要么全部回滚
- 幂等性: 回滚操作应该是可重复执行的
- 状态记录: 使用文件或变量记录已执行的操作
- 错误处理: 捕获所有可能的失败场景
- 资源清理: 确保在脚本退出时清理临时资源
选择哪种模式取决于你的具体需求:
- 简单操作:使用基本回滚模式
- 复杂操作:使用函数或事务模式
- 生产部署:使用检查点模式
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播