本文目录导读:

Shell脚本实现跳过回滚策略通常用于自动化部署、数据库迁移或任务执行中,以下提供几种常见实现方式:
版本号控制策略
#!/bin/bash
# 版本文件存储位置
VERSION_FILE="/tmp/deploy_version.txt"
CURRENT_VERSION=$(cat $VERSION_FILE 2>/dev/null || echo "0")
# 定义执行函数,带版本标记
execute_step() {
local step_name="$1"
local step_version="$2"
local step_command="$3"
# 跳过小于当前版本的步骤
if [ "$step_version" -le "$CURRENT_VERSION" ]; then
echo "[SKIP] $step_name (version $step_version <= current $CURRENT_VERSION)"
return 0
fi
echo "[EXECUTE] $step_name (version $step_version)"
eval "$step_command"
if [ $? -eq 0 ]; then
echo "$step_version" > "$VERSION_FILE"
echo "[SUCCESS] $step_name completed"
else
echo "[FAILED] $step_name - rolling back to version $CURRENT_VERSION"
echo "$CURRENT_VERSION" > "$VERSION_FILE" # 回滚版本号
return 1
fi
}
# 使用示例
execute_step "备份数据库" 1 "echo 'Backup completed'"
execute_step "更新配置" 2 "echo 'Config updated'"
execute_step "重启服务" 3 "echo 'Service restarted'"
状态文件标记法
#!/bin/bash
STATUS_DIR="/tmp/deploy_status"
mkdir -p "$STATUS_DIR"
# 执行和跳过逻辑
run_or_skip() {
local step_id="$1"
local step_name="$2"
local step_func="$3"
# 检查是否已成功执行
if [ -f "$STATUS_DIR/$step_id.completed" ]; then
echo "[SKIP] $step_name - already completed"
return 0
fi
# 检查是否有回滚标记
if [ -f "$STATUS_DIR/$step_id.rollback" ]; then
echo "[ROLLBACK] $step_name - undoing changes"
if [ -f "$STATUS_DIR/$step_id.rollback_script" ]; then
source "$STATUS_DIR/$step_id.rollback_script"
rm -f "$STATUS_DIR/$step_id.rollback"
rm -f "$STATUS_DIR/$step_id.completed"
fi
return 0
fi
# 执行步骤
echo "[EXECUTE] $step_name"
if $step_func; then
touch "$STATUS_DIR/$step_id.completed"
return 0
else
echo "[FAIL] $step_name - creating rollback marker"
touch "$STATUS_DIR/$step_id.rollback"
return 1
fi
}
# 示例函数
step1_backup() {
echo "Performing backup..."
return 0
}
step2_update() {
echo "Updating application..."
# 模拟失败
if [ "$RANDOM" -gt 10000 ]; then
return 1
fi
return 0
}
# 执行流程
run_or_skip "001" "Backup Database" step1_backup
run_or_skip "002" "Update Application" step2_update
数据库迁移回滚策略
#!/bin/bash
DB_NAME="myapp"
MIGRATIONS_DIR="/opt/migrations"
# 记录已执行的迁移
get_executed_migrations() {
mysql -e "SELECT migration_name FROM schema_migrations ORDER BY id;" "$DB_NAME" 2>/dev/null
}
# 记录迁移执行状态
mark_migration_executed() {
local name="$1"
mysql -e "INSERT INTO schema_migrations (migration_name, executed_at) VALUES ('$name', NOW());" "$DB_NAME"
}
# 带跳过回滚的迁移执行
execute_migration() {
local migration_file="$1"
local migration_name=$(basename "$migration_file" .sql)
# 检查是否已执行
if get_executed_migrations | grep -q "$migration_name"; then
echo "[SKIP] $migration_name already executed"
return 0
fi
echo "[EXECUTE] Migration: $migration_name"
# 执行迁移(捕获错误)
if mysql "$DB_NAME" < "$migration_file" 2>/tmp/migration_error; then
mark_migration_executed "$migration_name"
echo "[SUCCESS] $migration_name executed"
else
echo "[FAILED] Migration failed: $(cat /tmp/migration_error)"
# 自动回滚(如果有对应的回滚文件)
local rollback_file="${migration_file%.sql}_rollback.sql"
if [ -f "$rollback_file" ]; then
echo "[ROLLBACK] Executing rollback..."
mysql "$DB_NAME" < "$rollback_file"
fi
return 1
fi
}
# 执行所有待处理的迁移
for migration in $(ls $MIGRATIONS_DIR/*.sql | sort); do
execute_migration "$migration" || break
done
配置文件驱动策略
#!/bin/bash
# config.yaml 格式示例
: '
steps:
- name: "备份"
id: backup
command: "echo backup"
rollback: "echo restore_backup"
- name: "更新"
id: update
command: "echo update"
rollback: "echo revert_update"
'
# 读取配置并执行
execute_with_skip_rollback() {
local config_file="$1"
local state_file="${2:-/tmp/deploy_state.txt}"
# 读取已完成的步骤
declare -A completed_steps
if [ -f "$state_file" ]; then
while IFS= read -r line; do
completed_steps["$line"]=1
done < "$state_file"
fi
# 使用 yq 解析 YAML (需要安装 yq)
local steps_count=$(yq e '.steps | length' "$config_file")
for ((i=0; i<steps_count; i++)); do
local step_name=$(yq e ".steps[$i].name" "$config_file")
local step_id=$(yq e ".steps[$i].id" "$config_file")
local step_cmd=$(yq e ".steps[$i].command" "$config_file")
local rollback_cmd=$(yq e ".steps[$i].rollback" "$config_file")
# 跳过已完成的步骤
if [ "${completed_steps[$step_id]}" = "1" ]; then
echo "[SKIP] $step_name already completed"
continue
fi
# 执行步骤
echo "[EXECUTE] $step_name"
if eval "$step_cmd"; then
echo "$step_id" >> "$state_file"
echo "[SUCCESS] $step_name"
else
echo "[FAILED] $step_name - executing rollback"
eval "$rollback_cmd" || echo "[WARN] Rollback failed for $step_name"
return 1
fi
done
}
# 使用
execute_with_skip_rollback "deploy_config.yaml"
最佳实践建议
状态存储
# 使用数据库记录状态
mysql -e "
CREATE TABLE IF NOT EXISTS deploy_steps (
id INT AUTO_INCREMENT PRIMARY KEY,
step_name VARCHAR(255),
status ENUM('completed', 'failed', 'rolled_back'),
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"
异常处理
# 设置错误处理
set -eE
trap 'handle_error $LINENO' ERR
handle_error() {
local line=$1
echo "Error occurred at line $line"
# 执行全局回滚逻辑
}
幂等性设计
# 确保操作可以安全重复执行
safe_mkdir() {
local dir="$1"
if [ ! -d "$dir" ]; then
mkdir -p "$dir"
fi
}
safe_symlink() {
local target="$1"
local link="$2"
if [ -L "$link" ] && [ "$(readlink "$link")" = "$target" ]; then
return 0 # 已存在且指向正确
fi
ln -sf "$target" "$link"
}
完整示例:部署脚本
#!/bin/bash
# 配置
DEPLOY_DIR="/opt/app"
BACKUP_DIR="/opt/backups"
STATE_FILE="/tmp/deploy_state.txt"
# 初始化状态
mkdir -p "$(dirname "$STATE_FILE")"
# 检查并跳过已完成的步骤
check_step() {
local step="$1"
if grep -q "^$step$" "$STATE_FILE" 2>/dev/null; then
echo "[SKIP] $step"
return 0
fi
return 1
}
# 标记步骤完成
mark_complete() {
local step="$1"
echo "$step" >> "$STATE_FILE"
}
# 带回滚的执行
execute_step() {
local step="$1"
local action="$2"
local rollback="$3"
check_step "$step" && return 0
echo "[EXECUTE] $step"
if eval "$action"; then
mark_complete "$step"
else
echo "[FAIL] Rolling back: $step"
eval "$rollback" || echo "[WARN] Rollback failed"
return 1
fi
}
# 部署步骤
execute_step "backup" \
"cp -r $DEPLOY_DIR $BACKUP_DIR/backup_$(date +%Y%m%d)" \
"rm -rf $BACKUP_DIR/backup_$(date +%Y%m%d)"
execute_step "stop_service" \
"systemctl stop myapp" \
"systemctl start myapp"
execute_step "update_files" \
"cp -r /tmp/new_version/* $DEPLOY_DIR/" \
"cp -r $BACKUP_DIR/backup_$(date +%Y%m%d)/* $DEPLOY_DIR/"
execute_step "start_service" \
"systemctl start myapp" \
"systemctl stop myapp"
echo "Deployment completed successfully"
这些策略可以根据实际需求组合使用,关键是要确保操作的幂等性和可恢复性。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播