背景
在日常运维和开发工作中,日志文件、缓存文件或临时文件往往不断积累,如果不及时清理,不仅占用大量磁盘空间,还可能影响系统性能甚至导致磁盘满载的问题。手动清理繁琐且易出错,所以有了这个自动化脚本。
主要功能
- 指定目录和天数参数化
- 删除文件后同时清理空目录,保证目录结构整洁
- 日志输出支持 ANSI 彩色提示,方便日志浏览和诊断。
- Dry-run 模式,提供
-d/--dry-run参数,只显示即将删除的文件列表而不执行删除,方便先行检查 - 易用的帮助文档,无参数执行打印操作文档
脚本内容
#!/bin/bash
# ============================================================
# 清理旧文件脚本
# 功能:删除指定目录下超过30天未修改的文件
# 用法:./cleanup_old_files.sh <目录路径> [天数]
# 示例:./cleanup_old_files.sh /var/log/myapp 30
#
# 定时任务配置示例 (crontab -e):
# 每天凌晨3点执行:
# 0 3 * * * /path/to/cleanup_old_files.sh /var/log/myapp 30 >> /var/log/cleanup.log 2>&1
# ============================================================
# 默认配置
DEFAULT_DAYS=30
LOG_PREFIX="[cleanup_old_files]"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}${LOG_PREFIX} [INFO] $(date '+%Y-%m-%d %H:%M:%S') $1${NC}"
}
log_warn() {
echo -e "${YELLOW}${LOG_PREFIX} [WARN] $(date '+%Y-%m-%d %H:%M:%S') $1${NC}"
}
log_error() {
echo -e "${RED}${LOG_PREFIX} [ERROR] $(date '+%Y-%m-%d %H:%M:%S') $1${NC}"
}
# 格式化文件大小
format_size() {
local size=$1
if [[ $size -ge 1073741824 ]]; then
awk "BEGIN {printf \"%.2fGB\", $size/1073741824}"
elif [[ $size -ge 1048576 ]]; then
awk "BEGIN {printf \"%.2fMB\", $size/1048576}"
elif [[ $size -ge 1024 ]]; then
awk "BEGIN {printf \"%.2fKB\", $size/1024}"
else
echo "${size}B"
fi
}
# 显示帮助
show_help() {
echo "用法: $0 <目录路径> [天数]"
echo ""
echo "参数:"
echo " 目录路径 必填,要清理的目录路径"
echo " 天数 可选,删除多少天前的文件(默认: ${DEFAULT_DAYS})"
echo ""
echo "选项:"
echo " -h, --help 显示此帮助信息"
echo " -d, --dry-run 模拟运行,只显示要删除的文件,不实际删除"
echo ""
echo "示例:"
echo " $0 /var/log/myapp # 删除30天前的文件"
echo " $0 /var/log/myapp 7 # 删除7天前的文件"
echo " $0 /var/log/myapp 30 -d # 模拟运行,显示30天前要删除的文件"
echo ""
echo "定时任务配置 (crontab -e):"
echo " # 每天凌晨3点清理"
echo " 0 3 * * * /path/to/cleanup_old_files.sh /var/log/myapp 30 >> /var/log/cleanup.log 2>&1"
}
# 检查参数
DRY_RUN=false
TARGET_DIR=""
DAYS=$DEFAULT_DAYS
# 解析参数
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-d|--dry-run)
DRY_RUN=true
shift
;;
*)
if [[ -z "$TARGET_DIR" ]]; then
TARGET_DIR="$1"
elif [[ "$1" =~ ^[0-9]+$ ]]; then
DAYS="$1"
else
log_error "未知参数: $1"
show_help
exit 1
fi
shift
;;
esac
done
# 验证目录参数
if [[ -z "$TARGET_DIR" ]]; then
log_error "请提供目录路径"
show_help
exit 1
fi
# 检查目录是否存在
if [[ ! -d "$TARGET_DIR" ]]; then
log_error "目录不存在: $TARGET_DIR"
exit 1
fi
# 获取绝对路径
TARGET_DIR=$(cd "$TARGET_DIR" && pwd)
log_info "开始清理任务"
log_info "目标目录: $TARGET_DIR"
log_info "删除 ${DAYS} 天前的文件"
if [[ "$DRY_RUN" == "true" ]]; then
log_warn "模拟运行模式 - 不会实际删除文件"
fi
# 创建临时文件列表
TMP_FILE_LIST=$(mktemp)
trap "rm -f $TMP_FILE_LIST" EXIT
log_info "正在搜索超过 ${DAYS} 天未修改的文件..."
# 先找出所有文件并保存到临时文件
find "$TARGET_DIR" -type f -mtime +${DAYS} > "$TMP_FILE_LIST" 2>/dev/null || true
TOTAL_FILES=$(wc -l < "$TMP_FILE_LIST" | tr -d ' ')
log_info "找到 ${TOTAL_FILES} 个文件待处理"
if [[ $TOTAL_FILES -eq 0 ]]; then
log_info "没有找到需要删除的文件"
log_info "============ 清理完成 ============"
exit 0
fi
# 统计信息
TOTAL_SIZE=0
DELETED_COUNT=0
FAILED_COUNT=0
CURRENT=0
# 逐个处理文件
while IFS= read -r file; do
CURRENT=$((CURRENT + 1))
if [[ -f "$file" ]]; then
# 获取文件大小
FILE_SIZE=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file" 2>/dev/null || echo 0)
TOTAL_SIZE=$((TOTAL_SIZE + FILE_SIZE))
FILE_SIZE_STR=$(format_size $FILE_SIZE)
if [[ "$DRY_RUN" == "true" ]]; then
log_info "[${CURRENT}/${TOTAL_FILES}] [模拟] 将删除: $file ($FILE_SIZE_STR)"
DELETED_COUNT=$((DELETED_COUNT + 1))
else
if rm -f "$file" 2>/dev/null; then
log_info "[${CURRENT}/${TOTAL_FILES}] 已删除: $file ($FILE_SIZE_STR)"
DELETED_COUNT=$((DELETED_COUNT + 1))
else
log_error "[${CURRENT}/${TOTAL_FILES}] 删除失败: $file"
FAILED_COUNT=$((FAILED_COUNT + 1))
fi
fi
fi
done < "$TMP_FILE_LIST"
# 清理空目录
log_info "正在清理空目录..."
EMPTY_DIRS=0
while IFS= read -r dir; do
if [[ "$DRY_RUN" == "true" ]]; then
log_info "[模拟] 将删除空目录: $dir"
EMPTY_DIRS=$((EMPTY_DIRS + 1))
else
if rmdir "$dir" 2>/dev/null; then
log_info "已删除空目录: $dir"
EMPTY_DIRS=$((EMPTY_DIRS + 1))
fi
fi
done < <(find "$TARGET_DIR" -type d -empty 2>/dev/null || true)
# 输出统计信息
echo ""
log_info "============ 清理完成 ============"
log_info "找到的文件数: $TOTAL_FILES"
log_info "删除的文件数: $DELETED_COUNT"
if [[ $FAILED_COUNT -gt 0 ]]; then
log_warn "删除失败数: $FAILED_COUNT"
fi
log_info "释放空间: $(format_size $TOTAL_SIZE)"
log_info "清理的空目录数: $EMPTY_DIRS"
log_info "=================================="
exit 0
发表回复