文件同步脚本#

脚本说明#

文件同步脚本用于在本地和远程之间同步文件,支持双向同步、增量同步、排除文件等功能。

脚本代码#

#!/bin/bash

# 文件同步脚本
# 功能:在本地和远程之间同步文件
# 作者:System Admin
# 日期:2024-01-01

set -euo pipefail

# 配置变量
LOG_FILE="/var/log/file_sync.log"
SYNC_MODE="push"  # push/pull/bidirectional
SOURCE_DIR=""
DEST_DIR=""
EXCLUDE_FILE=""
DRY_RUN=false
VERBOSE=false
DELETE=false
COMPRESS=true

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 日志函数
log() {
    local level=$1
    shift
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] [$level] $@" | tee -a "$LOG_FILE"
}

log_info() {
    log "INFO" "$@"
}

log_error() {
    log "ERROR" "$@"
}

log_warning() {
    log "WARNING" "$@"
}

# 检查rsync
check_rsync() {
    if ! command -v rsync &> /dev/null; then
        log_error "rsync未安装,请先安装rsync"
        return 1
    fi
    return 0
}

# 检查目录
check_directories() {
    if [ ! -d "$SOURCE_DIR" ]; then
        log_error "源目录不存在: $SOURCE_DIR"
        return 1
    fi
    
    # 检查目标目录(远程目录可能不存在)
    if [[ ! "$DEST_DIR" =~ ^[a-zA-Z0-9]+@.*:.* ]]; then
        if [ ! -d "$DEST_DIR" ]; then
            log_error "目标目录不存在: $DEST_DIR"
            return 1
        fi
    fi
    
    return 0
}

# 构建rsync命令
build_rsync_command() {
    local cmd="rsync"
    
    # 添加选项
    if [ "$DRY_RUN" = true ]; then
        cmd="$cmd --dry-run"
    fi
    
    if [ "$VERBOSE" = true ]; then
        cmd="$cmd -v"
    fi
    
    if [ "$DELETE" = true ]; then
        cmd="$cmd --delete"
    fi
    
    if [ "$COMPRESS" = true ]; then
        cmd="$cmd -z"
    fi
    
    # 添加基本选项
    cmd="$cmd -avz --progress"
    
    # 添加排除文件
    if [ -n "$EXCLUDE_FILE" ] && [ -f "$EXCLUDE_FILE" ]; then
        cmd="$cmd --exclude-from=$EXCLUDE_FILE"
    fi
    
    echo "$cmd"
}

# 推送同步(本地到远程)
push_sync() {
    log_info "执行推送同步: $SOURCE_DIR -> $DEST_DIR"
    
    local rsync_cmd=$(build_rsync_command)
    $rsync_cmd "$SOURCE_DIR/" "$DEST_DIR/"
}

# 拉取同步(远程到本地)
pull_sync() {
    log_info "执行拉取同步: $DEST_DIR -> $SOURCE_DIR"
    
    local rsync_cmd=$(build_rsync_command)
    $rsync_cmd "$DEST_DIR/" "$SOURCE_DIR/"
}

# 双向同步
bidirectional_sync() {
    log_info "执行双向同步"
    
    # 第一步:推送同步
    log_info "第一步:推送同步"
    push_sync
    
    # 第二步:拉取同步
    log_info "第二步:拉取同步"
    pull_sync
    
    log_info "双向同步完成"
}

# 显示同步统计
show_sync_stats() {
    log_info "同步统计"
    
    # 查看同步的文件数量
    local file_count=$(find "$SOURCE_DIR" -type f | wc -l)
    log_info "源目录文件数量: $file_count"
    
    # 查看同步的数据量
    local dir_size=$(du -sh "$SOURCE_DIR" | cut -f1)
    log_info "源目录大小: $dir_size"
}

# 验证同步
verify_sync() {
    log_info "验证同步结果"
    
    # 比较文件数量
    local source_count=$(find "$SOURCE_DIR" -type f | wc -l)
    local dest_count
    
    if [[ "$DEST_DIR" =~ ^[a-zA-Z0-9]+@.*:.* ]]; then
        # 远程目录
        local remote_host=$(echo "$DEST_DIR" | cut -d: -f1)
        local remote_path=$(echo "$DEST_DIR" | cut -d: -f2)
        dest_count=$(ssh "$remote_host" "find '$remote_path' -type f | wc -l")
    else
        # 本地目录
        dest_count=$(find "$DEST_DIR" -type f | wc -l)
    fi
    
    log_info "源目录文件数: $source_count"
    log_info "目标目录文件数: $dest_count"
    
    if [ $source_count -eq $dest_count ]; then
        log_info "同步验证成功"
        return 0
    else
        log_warning "同步验证失败:文件数量不一致"
        return 1
    fi
}

# 创建排除文件
create_exclude_file() {
    local exclude_file="$1"
    
    log_info "创建排除文件: $exclude_file"
    
    {
        echo "# 排除临时文件"
        echo "*.tmp"
        echo "*.temp"
        echo "*~"
        echo ""
        
        echo "# 排除缓存文件"
        echo ".cache"
        echo "__pycache__"
        echo "node_modules"
        echo ""
        
        echo "# 排除日志文件"
        echo "*.log"
        echo "*.log.*"
        echo ""
        
        echo "# 排除系统文件"
        echo ".DS_Store"
        echo "Thumbs.db"
        echo ""
        
        echo "# 排除备份文件"
        echo "*.bak"
        echo "*.backup"
        echo "*~"
    } > "$exclude_file"
    
    log_info "排除文件创建完成"
}

# 显示帮助
show_help() {
    echo "用法: $0 [选项] <源目录> <目标目录>"
    echo ""
    echo "选项:"
    echo "  -m <模式>        同步模式(push/pull/bidirectional,默认: push)"
    echo "  -e <文件>        排除文件"
    echo "  -d              删除目标目录中多余的文件"
    echo "  -c              禁用压缩"
    echo "  -n              试运行模式(不实际同步)"
    echo "  -v              详细输出"
    echo "  -V              验证同步结果"
    echo "  -h              显示帮助信息"
    echo ""
    echo "示例:"
    echo "  # 推送同步(本地到远程)"
    echo "  $0 /data/ user@remote:/backup/"
    echo ""
    echo "  # 拉取同步(远程到本地)"
    echo "  $0 -m pull user@remote:/backup/ /data/"
    echo ""
    echo "  # 双向同步"
    echo "  $0 -m bidirectional /data/ user@remote:/backup/"
    echo ""
    echo "  # 使用排除文件"
    echo "  $0 -e exclude.txt /data/ user@remote:/backup/"
    echo ""
    echo "  # 删除多余文件"
    echo "  $0 -d /data/ user@remote:/backup/"
}

# 主函数
main() {
    # 解析选项
    while getopts "m:e:dcnvVh" opt; do
        case $opt in
            m)
                SYNC_MODE="$OPTARG"
                log_info "同步模式: $SYNC_MODE"
                ;;
            e)
                EXCLUDE_FILE="$OPTARG"
                log_info "排除文件: $EXCLUDE_FILE"
                ;;
            d)
                DELETE=true
                log_info "启用删除选项"
                ;;
            c)
                COMPRESS=false
                log_info "禁用压缩"
                ;;
            n)
                DRY_RUN=true
                log_info "启用试运行模式"
                ;;
            v)
                VERBOSE=true
                log_info "启用详细输出"
                ;;
            V)
                VERIFY=true
                log_info "启用验证"
                ;;
            h)
                show_help
                exit 0
                ;;
            *)
                log_error "无效选项: $opt"
                show_help
                exit 1
                ;;
        esac
    done
    
    shift $((OPTIND - 1))
    
    # 检查参数
    if [ $# -lt 2 ]; then
        log_error "缺少目录参数"
        show_help
        exit 1
    fi
    
    SOURCE_DIR="$1"
    DEST_DIR="$2"
    
    # 检查rsync
    if ! check_rsync; then
        exit 1
    fi
    
    # 检查目录
    if ! check_directories; then
        exit 1
    fi
    
    # 显示同步信息
    log_info "===== 开始文件同步 ====="
    log_info "源目录: $SOURCE_DIR"
    log_info "目标目录: $DEST_DIR"
    log_info "同步模式: $SYNC_MODE"
    
    if [ "$DRY_RUN" = true ]; then
        log_info "[DRY RUN] 试运行模式,不会实际同步文件"
    fi
    
    # 执行同步
    case $SYNC_MODE in
        push)
            push_sync
            ;;
        pull)
            pull_sync
            ;;
        bidirectional)
            bidirectional_sync
            ;;
        *)
            log_error "无效的同步模式: $SYNC_MODE"
            exit 1
            ;;
    esac
    
    # 显示统计信息
    show_sync_stats
    
    # 验证同步
    if [ "${VERIFY:-false}" = true ]; then
        verify_sync
    fi
    
    log_info "===== 文件同步完成 ====="
}

# 执行主函数
main "$@"

使用说明#

  1. 添加执行权限:

    chmod +x file_sync.sh
  2. 基本用法:

    # 推送同步(本地到远程)
    ./file_sync.sh /data/ user@remote:/backup/
    
    # 拉取同步(远程到本地)
    ./file_sync.sh -m pull user@remote:/backup/ /data/
    
    # 双向同步
    ./file_sync.sh -m bidirectional /data/ user@remote:/backup/
  3. 高级选项:

    # 使用排除文件
    ./file_sync.sh -e exclude.txt /data/ user@remote:/backup/
    
    # 删除目标目录中多余的文件
    ./file_sync.sh -d /data/ user@remote:/backup/
    
    # 试运行模式(不实际同步)
    ./file_sync.sh -n /data/ user@remote:/backup/
    
    # 详细输出
    ./file_sync.sh -v /data/ user@remote:/backup/
    
    # 验证同步结果
    ./file_sync.sh -V /data/ user@remote:/backup/
  4. 创建排除文件:

    # 创建默认排除文件
    ./file_sync.sh -e exclude.txt /data/ user@remote:/backup/

功能特点#

  • 支持推送、拉取、双向同步
  • 增量同步(只传输变化的文件)
  • 支持排除文件
  • 支持删除多余文件
  • 压缩传输
  • 试运行模式
  • 详细输出
  • 同步验证
  • 进度显示

依赖项#

  • rsync: 用于文件同步
  • ssh: 用于远程连接(同步到远程时需要)

注意事项#

  1. 确保rsync已安装
  2. 远程同步需要SSH访问权限
  3. 删除选项(-d)会永久删除文件,谨慎使用
  4. 建议先使用试运行模式(-n)查看将要同步的文件
  5. 大文件同步可能需要较长时间
  6. 确保网络连接稳定