背景简介
增量备份文件夹脚本笔记。
前置信息
- 系统:Debian 6.1.66-1 (2023-12-09) x86_64 GNU/Linux
详细信息
脚本详情
#!/bin/bash
# ==============================================================================
# Rsync Incremental Backup Script
# ==============================================================================
# 功能描述:
# 使用 rsync 对指定文件夹进行增量备份,保留指定天数的备份,
# 并将详细的日志记录到带时间戳的日志文件中。
#
# 依赖:
# - rsync
# - standard GNU coreutils (date, mkdir, find, rm, tee)
# ==============================================================================
# 函数:记录日志
log_message() {
local message="$1"
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $message" | tee -a "$LOG_FILE"
}
# 函数:显示使用说明并退出
usage() {
echo "使用方法: $0 -s <源目录> -d <备份目录> -l <日志目录> -r <保留天数>"
echo " -s 指定需要备份的源文件夹 (绝对路径)"
echo " -d 指定备份文件存储的目标文件夹 (绝对路径)"
echo " -l 指定日志文件存储的文件夹 (绝对路径)"
echo " -r 指定备份保留天数 (正整数)"
echo " -h 显示此帮助信息"
exit 1
}
# 初始化变量
SOURCE_DIR=""
BACKUP_DIR=""
LOG_DIR=""
RETENTION_DAYS=""
# 使用 getopts 解析参数
# ":s:d:l:r:h" 表示接受 -s, -d, -l, -r, -h 五个选项,其中 s,d,l,r 需要参数
while getopts ":s:d:l:r:h" opt; do
case ${opt} in
s)
SOURCE_DIR="$OPTARG"
;;
d)
BACKUP_DIR="$OPTARG"
;;
l)
LOG_DIR="$OPTARG"
;;
r)
RETENTION_DAYS="$OPTARG"
;;
h)
usage
;;
\?) # 当传入无效选项时
echo "无效选项: -$OPTARG" >&2
usage
;;
:) # 当选项缺少参数时
echo "选项 -$OPTARG 需要一个参数." >&2
usage
;;
esac
done
# 检查是否所有必需的参数都已提供
if [[ -z "$SOURCE_DIR" || -z "$BACKUP_DIR" || -z "$LOG_DIR" || -z "$RETENTION_DAYS" ]]; then
echo "错误:缺少必需的参数。" >&2
usage
fi
# 检查保留天数是否为正整数
if ! [[ "$RETENTION_DAYS" =~ ^[0-9]+$ ]]; then
echo "错误:保留天数 (-r) 必须是一个正整数。" >&2
exit 1
fi
# ------------------------------------------------------------------------------
# 脚本主逻辑
# ------------------------------------------------------------------------------
# --- 1. 初始化和前置检查 ---
# 检查 rsync 是否已安装
if ! command -v rsync &> /dev/null; then
echo "[错误] rsync 未安装。请先安装 rsync。"
exit 1
fi
# 检查源目录是否存在且可读
if [ ! -r "$SOURCE_DIR" ]; then
echo "[错误] 源目录 '$SOURCE_DIR' 不存在或不可读。"
exit 1
fi
# 创建日志和备份目录 (如果不存在)
mkdir -p "$LOG_DIR" "$BACKUP_DIR"
if [ $? -ne 0 ]; then
echo "[错误] 无法创建日志目录 '$LOG_DIR' 或备份目录 '$BACKUP_DIR'。请检查权限。"
exit 1
fi
# 生成时间戳
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
# 定义本次备份的目录和日志文件
CURRENT_BACKUP_DIR="$BACKUP_DIR/backup_$TIMESTAMP"
LOG_FILE="$LOG_DIR/backup_$TIMESTAMP.log"
# --- 2. 开始备份流程 ---
log_message "INFO" "========== 备份任务开始 =========="
log_message "INFO" "源目录: $SOURCE_DIR"
log_message "INFO" "目标备份目录: $CURRENT_BACKUP_DIR"
# 查找最新的备份目录,用于 --link-dest 参数
LATEST_BACKUP=$(ls -dt "$BACKUP_DIR"/backup_* 2>/dev/null | head -n 1)
# 构建 rsync 命令参数
RSYNC_ARGS=(-a -v --delete)
if [ -n "$LATEST_BACKUP" ] && [ -d "$LATEST_BACKUP" ]; then
log_message "INFO" "找到上一次备份: $LATEST_BACKUP,将作为硬链接基准。"
RSYNC_ARGS+=(--link-dest="$LATEST_BACKUP")
else
log_message "ERROR" "未找到上一次备份,将执行首次完整备份。"
fi
# 执行 rsync 备份
# 注意: SOURCE_DIR 后面的斜杠 / 表示只复制目录内容,而不复制目录本身
log_message "INFO" "正在执行 rsync 命令..."
rsync "${RSYNC_ARGS[@]}" "$SOURCE_DIR/" "$CURRENT_BACKUP_DIR/" 2>&1 | tee -a "$LOG_FILE"
RSYNC_EXIT_CODE=$?
# 检查 rsync 是否成功
if [ $RSYNC_EXIT_CODE -eq 0 ]; then
log_message "INFO" "Rsync 备份成功完成。"
else
log_message "ERROR" "[错误] Rsync 备份失败,退出码: $RSYNC_EXIT_CODE。请检查日志文件 '$LOG_FILE' 获取详细信息。"
# 可以选择在失败时删除不完整的备份目录
# rm -rf "$CURRENT_BACKUP_DIR"
exit $RSYNC_EXIT_CODE
fi
# --- 3. 清理旧备份 ---
log_message "INFO" "开始清理超过 $RETENTION_DAYS 天的旧备份..."
# 使用 find 命令查找并删除旧备份
# -maxdepth 1: 只在指定目录下查找,不进入子目录
# -type d: 只查找目录
# -name "backup_*": 匹配我们的备份目录命名格式
# -mtime +$RETENTION_DAYS: 查找修改时间超过 N 天的文件/目录
# -exec rm -rf {} +: 对找到的目录执行删除命令
DELETED_COUNT=$(find "$BACKUP_DIR" -maxdepth 1 -type d -name "backup_*" -mtime +$RETENTION_DAYS -print -exec rm -rf {} + | wc -l)
if [ $DELETED_COUNT -gt 0 ]; then
log_message "INFO" "清理完成,共删除了 $DELETED_COUNT 个旧备份目录。"
else
log_message "INFO" "没有找到需要清理的旧备份。"
fi
# --- 4. 任务结束 ---
log_message "INFO" "========== 备份任务成功结束 =========="
exit 0
以上便是本文的全部内容,感谢您的阅读,如遇到任何问题,欢迎在评论区留言讨论。