备份日志
#!/bin/bash
set -euo pipefail
set -u # 启用未定义变量检查
# ================================== 配置参数 ==================================
TARGET_DIR="/data/webapps_djypt_gdyc/logs" # 执行目录(脚本所在目录或当前工作目录)
BACKUP_ROOT="/backup/dated_logs" # 备份根目录
RETENTION_DAYS=7 # 备份保留天数
BACKUP_LOG="/var/log/backup_dated_logs.log" # 脚本运行日志
DATE_PATTERN="2[0-9]{3}-[0-1][0-9]-[0-3][0-9]" # 日志文件名中的日期格式(YYYY-MM-DD)
# ==============================================================================# 初始化变量
BACKUP_TODAY_DIR="${BACKUP_ROOT}/"
DUPLICATE_MARKER="_duplicate_$(date +"%H%M%S")" # 重复文件标记(加时间戳避免冲突)# 日志函数
log() {echo "[$(date +"%Y-%m-%d %H:%M:%S")] $1" >> "${BACKUP_LOG}"
}# 初始化
log "===== 开始每日带日期日志备份 ====="
mkdir -p "${BACKUP_TODAY_DIR}" || { log "错误:无法创建备份目录 ${BACKUP_TODAY_DIR}"; exit 1; }# 1. 查找目标目录下所有含日期格式的日志文件
# 格式要求:文件名包含 YYYYMMDD 日期(如 app_20251018.log、20251018_error.log)
find_target_logs() {find "${TARGET_DIR}" -type f -name "*.gz" -mtime -3 |grep -E "${DATE_PATTERN}"find "${TARGET_DIR}" -type f -name "*.gz" |grep -E "${DATE_PATTERN}"
}# 2. 提取文件的上两级目录结构(用于备份时保留)
# 例:源路径 a/b/c/d/log_2025-10-18.log → 上两级目录为 c/d → 备份路径中保留 c/d
get_upper_two_dirs() {local full_path="$1"local rel_path="${full_path#${TARGET_DIR}/}" # 相对于目标目录的路径local dir_depth=$(echo "${rel_path}" | tr '/' '\n' | wc -l) # 目录深度(含文件名)if [ "${dir_depth}" -le 2 ]; then# 若深度≤2(如直接在目标目录或下一级目录),保留完整相对路径echo "$(dirname "${rel_path}")"else# 取上两级目录(通过逆向切割实现)echo "${rel_path}" | rev | cut -d'/' -f3- | rev | cut -d'/' -f1-fi
}# 3. 检查备份目录中是否存在同名文件(验证名称重复)
is_name_duplicate() {local target_name="$1"local backup_subdir="$2"[ -f "${BACKUP_TODAY_DIR}/${backup_subdir}/${target_name}" ]
}# 4. 备份文件并处理重复
backup_log_file() {local src_file="$1"local file_name=$(basename "${src_file}")local upper_two_dirs=$(get_upper_two_dirs "${src_file}")local backup_subdir="${upper_two_dirs}"local dest_dir="${BACKUP_TODAY_DIR}/${backup_subdir}"local dest_file="${dest_dir}/${file_name}"# 创建备份子目录(保留上两级结构)mkdir -p "${dest_dir}" || { log "警告:无法创建备份子目录 ${dest_dir},跳过文件 ${src_file}"; return 1; }# 检查名称重复if is_name_duplicate "${file_name}" "${backup_subdir}"; thenlocal new_file_name="${file_name%.log}_${DUPLICATE_MARKER}.log" # 处理.log后缀new_file_name="${new_file_name%.gz}_${DUPLICATE_MARKER}.gz" # 处理.gz后缀(如需)dest_file="${dest_dir}/${new_file_name}"log "发现重复文件名 ${file_name},重命名为 ${new_file_name}"fi# 复制文件(保留权限和属性)cp -a "${src_file}" "${dest_file}" || { log "错误:备份 ${src_file} 失败"; return 1; }# 验证备份完整性(对比文件大小)if [ $(stat -c%s "${src_file}") -ne $(stat -c%s "${dest_file}") ]; thenlog "错误:备份文件 ${dest_file} 损坏(大小不匹配),已删除"rm -f "${dest_file}"return 1filog "备份成功:${src_file} → ${dest_file}"return 0
}# 5. 清理过期备份
cleanup_expired() {log "清理 ${RETENTION_DAYS} 天前的备份..."find "${BACKUP_ROOT}" -type d -name "20[0-9]{6}" -mtime +${RETENTION_DAYS} -exec rm -rf {} + 2>/dev/null
}# 主流程
main() {local target_logs=$(find_target_logs)if [ -z "${target_logs}" ]; thenlog "警告:未找到日志文件"cleanup_expiredlog "===== 备份结束 ====="exit 0fi# 批量备份日志文件echo "${target_logs}"|while IFS= read -r log_file; dobackup_log_file "${log_file}"done# 清理过期备份cleanup_expiredlog "===== 备份结束 ====="
}# 启动主流程
main
好学若饥,谦卑若愚