脚本设计

功能

  1. 第一次运行脚本时进行全量同步。
  2. 后续每次运行只同步新增或修改的文件(增量同步)。
  3. 增加挂载和卸载 B 磁盘的逻辑。

脚本内容: 编辑 /usr/local/bin/backup_diskA_to_diskB.sh

#!/bin/bash

# 配置变量
SRC="/mnt/diskA/"                         # A 磁盘路径
DEST_MOUNT="/mnt/diskB"                   # B 磁盘挂载点
DEVICE_UUID="123e4567-e89b-12d3-a456-426614174000"  # 替换为实际UUID
LOG_FILE="/var/log/backup.log"

# 检查并挂载 B 磁盘
if ! mount | grep -q "$DEST_MOUNT"; then
    mount -U "$DEVICE_UUID" "$DEST_MOUNT"
    if [ $? -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Failed to mount UUID=$DEVICE_UUID" >> "$LOG_FILE"
        exit 1
    fi
fi

# 确保目标目录存在
mkdir -p "$DEST_MOUNT"

# 开始同步(增量同步)
rsync -av --delete "$SRC" "$DEST_MOUNT"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') Incremental backup completed successfully" >> "$LOG_FILE"
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Incremental backup failed" >> "$LOG_FILE"
    umount "$DEST_MOUNT"
    exit 1
fi

# 卸载目标磁盘
umount "$DEST_MOUNT"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') Disk UUID=$DEVICE_UUID unmounted successfully" >> "$LOG_FILE"
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Failed to unmount UUID=$DEVICE_UUID" >> "$LOG_FILE"
    exit 1
fi

配置与使用

1. 设置脚本执行权限

sudo chmod +x /usr/local/bin/backup_diskA_to_diskB.sh

2. 定时任务配置

使用 cron 设置每天 17:00 自动执行脚本:

crontab -e

添加以下内容:

0 17 * * * /usr/local/src/backups/disk/backup_disk.sh

工作原理

  1. 首次运行
    • 如果目标目录为空,rsync 会全量复制 A 磁盘的所有数据到 B 磁盘。
    • 将数据完整同步到 /mnt/diskB
  2. 后续运行
    • rsync 会检查源和目标的文件状态(文件大小、修改时间等)。
    • 只同步新增或被修改的文件。
    • 删除目标目录中已被源目录删除的文件(通过 --delete 参数)。

测试与验证

  1. 手动运行脚本:

    sudo /usr/local/bin/backup_diskA_to_diskB.sh
    

    验证挂载、增量同步和卸载是否正常。

  2. 检查同步结果:

    • /mnt/diskB 查看是否成功同步了 /mnt/diskA 的数据。
    • 检查 /var/log/backup.log 是否记录了备份的状态。
  3. 修改 /mnt/diskA 中的文件,再次运行脚本,确认增量同步只同步了变化部分。


优化建议

  1. 日志更详细:在 rsync 中添加 --log-file 参数,将每次同步的详细信息记录到独立日志文件:

    rsync -av --delete --log-file=/var/log/rsync.log "$SRC" "$DEST_MOUNT"
    
  2. 排除不必要文件:如果有不需要同步的文件或目录,可以使用 --exclude 参数。例如:

    rsync -av --delete --exclude "temp/" --exclude "*.log" "$SRC" "$DEST_MOUNT"
    
  3. 并发保护:避免多个脚本实例同时运行,可添加锁文件:

    LOCK_FILE="/tmp/backup.lock"
    if [ -f "$LOCK_FILE" ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Script already running" >> "$LOG_FILE"
        exit 1
    fi
    touch "$LOCK_FILE"
    trap "rm -f $LOCK_FILE" EXIT
    

这样可以高效实现全量+增量备份,同时确保数据安全!

完整脚本

#!/bin/bash

# 配置变量
SRC="/mnt/diskA/"                         # A 磁盘路径
DEST_MOUNT="/mnt/diskB"                   # B 磁盘挂载点
DEVICE_UUID="123e4567-e89b-12d3-a456-426614174000"  # 替换为实际UUID
LOG_FILE="/var/log/backup.log"            # 总体日志文件
RSYNC_LOG="/var/log/rsync.log"            # rsync 同步详细日志
LOCK_FILE="/tmp/backup.lock"              # 锁文件

# 排除文件和目录
EXCLUDES=("--exclude=temp/" "--exclude=*.log")  # 配置排除的规则

# 检查并发运行
if [ -f "$LOCK_FILE" ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Script already running" >> "$LOG_FILE"
    exit 1
fi

# 创建锁文件
touch "$LOCK_FILE"

# 在脚本结束时清理锁文件
trap "rm -f $LOCK_FILE" EXIT

# 检查并挂载 B 磁盘
if ! mount | grep -q "$DEST_MOUNT"; then
    mount -U "$DEVICE_UUID" "$DEST_MOUNT"
    if [ $? -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Failed to mount UUID=$DEVICE_UUID" >> "$LOG_FILE"
        exit 1
    fi
fi

# 确保目标目录存在
mkdir -p "$DEST_MOUNT"

# 开始同步(增量同步)
rsync -av --delete "${EXCLUDES[@]}" --log-file="$RSYNC_LOG" "$SRC" "$DEST_MOUNT"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') Incremental backup completed successfully" >> "$LOG_FILE"
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Incremental backup failed" >> "$LOG_FILE"
    umount "$DEST_MOUNT"
    exit 1
fi

# 卸载目标磁盘
umount "$DEST_MOUNT"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') Disk UUID=$DEVICE_UUID unmounted successfully" >> "$LOG_FILE"
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Failed to unmount UUID=$DEVICE_UUID" >> "$LOG_FILE"
    exit 1
fi

附带邮件通知

安装mailx

sudo yum install mailx -y

配置邮件发送

  • 配置 /etc/mail.rc 或使用您公司邮箱的 SMTP 设置。

  • 示例(以 163为例):在 /etc/mail.rc 中添加以下内容:

    在最后添加
    
    ##改成自己的163邮箱
    set from=12345678901@163.com
    set smtp=smtp.163.com 
    ##改成自己的163邮箱
    set smtp-auth-user=12345678901@163.com 	
    set smtp-auth-password=授权密码						
    set smtp-auth=login
    
    

    测试:

    第一种
    mail -s "主题" username
    ​	邮件内容
    ​	ctrl+d
    
    第二种
    echo "hello"	|mail -s "邮件主题" usename
    
    第三种
    发送附件
    echo "hello"	|mail -s "邮件主题" -a /file usename
    

改进脚本

#!/bin/bash

# 配置变量
SRC="/mnt/diskA/"                         # A 磁盘路径
DEST_MOUNT="/mnt/diskB"                   # B 磁盘挂载点
DEVICE_UUID="123e4567-e89b-12d3-a456-426614174000"  # 替换为实际UUID
LOG_FILE="/var/log/backup.log"            # 总体日志文件
RSYNC_LOG="/var/log/rsync.log"            # rsync 同步详细日志
LOCK_FILE="/tmp/backup.lock"              # 锁文件
EMAIL="your_email@example.com"            # 接收通知的邮箱

# 排除文件和目录
EXCLUDES=("--exclude=temp/" "--exclude=*.log")  # 配置排除的规则

# 并发检查
if [ -f "$LOCK_FILE" ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Script already running" >> "$LOG_FILE"
    echo "Backup script is already running. Exiting..." | mail -s "Backup Failed" "$EMAIL"
    exit 1
fi
touch "$LOCK_FILE"
trap "rm -f $LOCK_FILE" EXIT

# 发送备份开始通知
echo "Backup started at $(date)" | mail -s "Backup Started" "$EMAIL"

# 挂载磁盘
if ! mount | grep -q "$DEST_MOUNT"; then
    mount -U "$DEVICE_UUID" "$DEST_MOUNT"
    if [ $? -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Failed to mount UUID=$DEVICE_UUID" >> "$LOG_FILE"
        echo "Failed to mount disk UUID=$DEVICE_UUID at $(date)" | mail -s "Backup Failed" "$EMAIL"
        exit 1
    fi
fi

# 确保目标目录存在
mkdir -p "$DEST_MOUNT"

# 同步数据
rsync -av --delete "${EXCLUDES[@]}" --log-file="$RSYNC_LOG" "$SRC" "$DEST_MOUNT"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') Incremental backup completed successfully" >> "$LOG_FILE"
    echo "Backup completed successfully at $(date)" | mail -s "Backup Success" "$EMAIL"
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Incremental backup failed" >> "$LOG_FILE"
    echo "Backup failed during rsync operation at $(date)" | mail -s "Backup Failed" "$EMAIL"
    umount "$DEST_MOUNT"
    exit 1
fi

# 卸载磁盘
umount "$DEST_MOUNT"
if [ $? -eq 0 ]; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') Disk UUID=$DEVICE_UUID unmounted successfully" >> "$LOG_FILE"
else
    echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: Failed to unmount UUID=$DEVICE_UUID" >> "$LOG_FILE"
    echo "Failed to unmount disk UUID=$DEVICE_UUID at $(date)" | mail -s "Backup Failed" "$EMAIL"
    exit 1
fi