#!/bin/bash # ================================================ # KR数据同步后 MD5 校验与重试脚本 # 功能:对比源目录与远程目标目录的 MD5(基于相对路径),不一致则重新同步 # 用法:./kr_data_sync_verify.sh [YYYYMMDD] # ================================================ # ---------- 配置参数 ---------- #SRC_BASE="/home/sysop/kr_md_save_pkt_loss_v5/data/stockdata" #南方 SRC_BASE="/home/sysop/kr_md_save_centos7_9_20260317/data/stockdata" #金桥 DEST_HOST="swdata@119.167.194.234" DEST_PORT="60000" #DEST_BASE="/mnt/data1/data_new_nf/data/stockdata" #南方 DEST_BASE="/mnt/data1/data_new/data/stockdata" #金桥 DEST_MARK_BASE="/mnt/data1/md5" SSH_OPTS="-o ConnectTimeout=30 -o BatchMode=yes -o StrictHostKeyChecking=no -o ServerAliveInterval=60 -o ServerAliveCountMax=3" LOG_DIR="/var/log/kr_data_sync" LOG_FILE="$LOG_DIR/verify_$(date +%Y%m%d).log" MAX_RETRIES=10 mkdir -p "$LOG_DIR" # ---------- 日志函数 ---------- log_info() { echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" | tee -a "$LOG_FILE" } log_error() { echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" | tee -a "$LOG_FILE" } usage() { echo "用法: $0 [YYYYMMDD]" exit 1 } check_dependencies() { command -v rsync &>/dev/null || { log_error "请安装 rsync"; exit 1; } command -v md5sum &>/dev/null || { log_error "请安装 md5sum"; exit 1; } } check_ssh() { log_info "检查 SSH 连接..." ssh -p "$DEST_PORT" $SSH_OPTS "$DEST_HOST" "echo ok" &>/dev/null || { log_error "SSH 连接失败" exit 1 } log_info "SSH 连接正常" } check_remote_md5sum() { ssh -p "$DEST_PORT" $SSH_OPTS "$DEST_HOST" "command -v md5sum" &>/dev/null || { log_error "远程主机缺少 md5sum" exit 1 } log_info "远程 md5sum 可用" } ensure_remote_mark_dir() { ssh -p "$DEST_PORT" $SSH_OPTS "$DEST_HOST" "mkdir -p '$DEST_MARK_BASE'" &>/dev/null || { log_error "无法创建远程标记目录 $DEST_MARK_BASE" exit 1 } log_info "远程标记目录已确认: $DEST_MARK_BASE" } # ========== 生成相对路径的 MD5 列表 ========== generate_local_md5() { local dir="$1" local tmpfile=$(mktemp) # 进入源目录,使用相对路径(以 ./ 开头) (cd "$dir" && find . -type f -print0 2>/dev/null | xargs -0 md5sum 2>/dev/null | sort -k2) > "$tmpfile" echo "$tmpfile" } generate_remote_md5() { local dir="$1" local tmpfile=$(mktemp) # 远程进入目标目录,同样使用相对路径 ssh -p "$DEST_PORT" $SSH_OPTS "$DEST_HOST" "cd '$dir' && find . -type f -print0 2>/dev/null | xargs -0 md5sum 2>/dev/null | sort -k2" > "$tmpfile" 2>/dev/null echo "$tmpfile" } # ==================================================== compare_md5() { local local_list="$1" local remote_list="$2" local diff_file=$(mktemp) if [ ! -s "$local_list" ]; then log_error "本地文件列表为空" rm -f "$diff_file" return 1 fi if diff "$local_list" "$remote_list" > "$diff_file" 2>&1; then log_info "MD5 校验一致" rm -f "$diff_file" return 0 else log_error "MD5 校验不一致,差异如下:" cat "$diff_file" | tee -a "$LOG_FILE" rm -f "$diff_file" return 1 fi } do_sync() { local src="$1" local dest="$2" log_info "开始同步: $src -> $dest" rsync -avz --progress --delete \ -e "ssh -p $DEST_PORT $SSH_OPTS" \ "$src/" \ "$DEST_HOST:$dest/" 2>&1 | tee -a "$LOG_FILE" local sync_result=${PIPESTATUS[0]} if [ $sync_result -eq 0 ]; then log_info "同步完成" return 0 else log_error "同步失败,退出码: $sync_result" return 1 fi } create_mark_file() { local date_str="$1" #local remote_mark_file="$DEST_MARK_BASE/${date_str}_nf" #南方 local remote_mark_file="$DEST_MARK_BASE/${date_str}_jq" #金桥 echo "Sync completed and verified at $(date -u '+%Y-%m-%d %H:%M:%S UTC')" | \ ssh -p "$DEST_PORT" $SSH_OPTS "$DEST_HOST" "cat > '$remote_mark_file'" if [ $? -eq 0 ]; then log_info "已创建标记文件: $remote_mark_file" else log_error "创建标记文件失败" exit 1 fi } main() { local target_date="$1" [ -z "$target_date" ] && target_date=$(date +%Y%m%d) if ! [[ "$target_date" =~ ^[0-9]{8}$ ]]; then log_error "日期格式必须为 YYYYMMDD" usage fi local src_dir="$SRC_BASE/$target_date" local dest_dir="$DEST_BASE/$target_date" local remote_mark_file="$DEST_MARK_BASE/$target_date" log_info "========== 开始 MD5 校验与同步任务 ==========" log_info "日期: $target_date" log_info "源目录: $src_dir" log_info "目标目录: $dest_dir" log_info "标记文件: $remote_mark_file" [ ! -d "$src_dir" ] && { log_error "源目录不存在: $src_dir"; exit 1; } check_dependencies check_ssh check_remote_md5sum ensure_remote_mark_dir local retry_count=0 local success=false while [ $retry_count -lt $MAX_RETRIES ]; do retry_count=$((retry_count + 1)) log_info "===== 第 $retry_count 次校验 =====" local local_md5=$(generate_local_md5 "$src_dir") local remote_md5=$(generate_remote_md5 "$dest_dir") if compare_md5 "$local_md5" "$remote_md5"; then success=true rm -f "$local_md5" "$remote_md5" break else rm -f "$local_md5" "$remote_md5" log_info "MD5 不一致,执行同步..." if ! do_sync "$src_dir" "$dest_dir"; then log_error "同步失败,终止重试" exit 1 fi sleep 5 fi done if [ "$success" = true ]; then log_info "经过 $retry_count 次校验,MD5 已一致" create_mark_file "$target_date" log_info "任务完成,已生成标记文件" else log_error "达到最大重试次数 $MAX_RETRIES,仍然无法使 MD5 一致" exit 1 fi log_info "========== 任务结束 ==========" } if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then usage fi main "$1"