定时删除过期日志的脚本

wen 实用脚本 2

从运维小白到自动清理高手的完整指南

目录导读


为什么你的服务器需要定时删除过期日志?

日志文件是系统运行的重要记录,但如果不加管理,它们会像“数据垃圾”一样迅速膨胀,在实际运维中,我们经常遇到以下场景:

定时删除过期日志的脚本

  • 某天磁盘告警,发现 /var/log/ 占用超过80%的磁盘空间
  • 应用日志每天增长500MB,45天后导致 /home/ 分区爆满
  • 审计要求的日志保留30天,但手动删除又繁琐又容易误删

当你使用一个 定时删除过期日志的脚本 后,所有问题都会迎刃而解,该脚本的核心价值在于:

  1. 自动清理:无需人工介入,自动查找并删除超过指定天数的日志文件
  2. 节省磁盘:彻底避免“日志撑爆硬盘”导致服务中断的悲剧
  3. 合规保留:精准控制日志保留期限(如30天、60天、180天)

一个真实的案例:某电商公司线上服务器因为日志一个月未清理,导致磁盘写满,最终数据库宕机2小时,事后他们紧急部署了定时删除过期日志的脚本,至今未再出现同类事故。


定时删除日志脚本的核心原理

要编写一个强大的日志清理脚本,你需要理解三个核心元素:

文件时间戳识别

Linux系统中,每个文件有三个时间戳:

  • mtime(修改时间):文件内容最后被修改的时间
  • ctime(状态更改时间):文件权限或属性发生变化的时间
  • atime(访问时间):文件最后被读取的时间

对于日志文件,我们通常基于 mtime 判断是否过期

查找并匹配目标文件

使用 find 命令是脚本的关键。

find /var/log/ -name "*.log" -type f -mtime +30

这表示:在 /var/log/ 下查找所有以 .log 且最后修改时间超过30天的普通文件。

删除或压缩操作

找到文件后,你可以选择:

  • 直接删除-deleteexec rm -f {} \;
  • 压缩归档:用 gzip 压缩后删除源文件,保留 .gz 压缩包
  • 移至备份目录:配合 mv 命令实现“软删除”

手写一个完整的定时删除日志脚本(附代码)

以下是一个可直接部署的 bash 脚本,功能包括:

  • 自定义要清理的目录
  • 自定义保留天数
  • 支持白名单(跳过重要日志)
  • 生成清理日志,方便审计

脚本文件名:clean_expired_logs.sh

#!/bin/bash
# 配置区 —— 根据你的实际环境修改以下变量
LOG_DIRS=("/var/log" "/home/app/logs" "/data/wwwlogs")   # 要清理的日志目录
RETENTION_DAYS=30                                         # 保留天数(例如30天)
EXCLUDED_PATTERNS=("*.gz" "important.log")                # 不删除的文件模式(白名单)
SCRIPT_LOG="/var/log/log_cleaner.log"                     # 脚本自身的运行日志
# 函数:输出带时间戳的日志
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${SCRIPT_LOG}"
}
# 开始清理
log "========== 定时删除过期日志脚本开始运行 =========="
for dir in "${LOG_DIRS[@]}"; do
    if [ ! -d "$dir" ]; then
        log "目录 [${dir}] 不存在,跳过"
        continue
    fi
    log "正在扫描目录: ${dir}"
    # 构建排除参数(跳过白名单文件)
    exclude_opts=""
    for pattern in "${EXCLUDED_PATTERNS[@]}"; do
        exclude_opts="${exclude_opts} -not -name \"${pattern}\""
    done
    # 查找并删除超过保留天数的日志文件
    find "$dir" -type f \( -name "*.log" -o -name "*.txt" \) \
        -mtime +${RETENTION_DAYS} \
        ${exclude_opts} \
        -exec rm -f {} \; \
        -print | while read deleted_file; do
            log "已删除过期日志: ${deleted_file}"
        done
    # 可选:同时删除空的日志目录(如果结构允许)
    find "$dir" -type d -empty -delete 2>/dev/null
done
log "========== 定时删除过期日志脚本运行完成 =========="
log ""

如何使用这个脚本?

  1. 保存脚本:将上述内容保存为 /usr/local/bin/clean_expired_logs.sh
  2. 赋予执行权限chmod +x /usr/local/bin/clean_expired_logs.sh
  3. 首次测试运行/usr/local/bin/clean_expired_logs.sh
  4. 查看运行日志tail -f /var/log/log_cleaner.log

如何用crontab实现自动化运行

仅仅写好脚本还不够,你需要让系统定时自动执行,Linux 的 crontab 是最好的选择。

步骤1:编辑 crontab 任务

执行命令:crontab -e

步骤2:添加定时任务

以下是一些常用配置:

# 每天凌晨2点执行一次
0 2 * * * /usr/local/bin/clean_expired_logs.sh
# 每天凌晨3点半执行(避开高峰期)
30 3 * * * /usr/local/bin/clean_expired_logs.sh
# 每10天执行一次(低频场景)
0 0 */10 * * /usr/local/bin/clean_expired_logs.sh

步骤3:验证定时任务

  • 查看已添加的任务:crontab -l
  • 查看 cron 服务是否运行:systemctl status crondservice cron status
  • 查看脚本执行日志:tail -f /var/log/log_cleaner.log

执行频率建议:对于日志量较大的生产服务器,建议每天执行一次,保留天数设为 30~60 天,对于日志量较小的测试服务器,可以每周或每两周执行一次。


常见问题问答(FAQ)

问1:这个脚本会不会误删正在写入的日志文件?

答:一般不会。 因为脚本基于 mtime(最后修改时间)判断,正在写入的日志文件,其 mtime 会持续更新,只要保留天数设置合理(如30天),就不会误删当前正在使用的文件,如果担心,可以增加 -not -name "access.log" 等白名单。

问2:我想保留某些特定的日志文件,怎么办?

答:使用脚本中的 EXCLUDED_PATTERNS 数组。

EXCLUDED_PATTERNS=("*.gz" "audit.log" "security.log")

这样所有 *.gz 压缩文件以及名为 audit.log security.log 的文件都会被跳过。

问3:脚本在Windows上能用吗?

答:不能直接使用。 本脚本基于 bash 和 Linux 命令,Windows环境你需要使用 PowerShell 脚本,类似这样:

Get-ChildItem -Path "C:\Logs" -Filter "*.log" | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | Remove-Item

然后用 Windows 任务计划程序设定定时执行。

问4:我每天生成的日志很大,保留30天但依然不够?

答:可以考虑“压缩+删除”模式。 先将超过7天的日志压缩为 .gz,再删除超过30天的 .gz 文件,这样即节省空间,又满足审计需要,脚本改造如下:

# 压缩超过7但小于30天的日志
find /var/log -name "*.log" -type f -mtime +7 -mtime -30 -exec gzip {} \;
# 删除超过30天的所有日志(包括压缩包)
find /var/log -type f \( -name "*.log" -o -name "*.gz" \) -mtime +30 -exec rm -f {} \;

问5:如何让脚本只删除而不打印大段输出?

答:将标准输出重定向到 /dev/null 在 cron 任务中配置:

0 2 * * * /usr/local/bin/clean_expired_logs.sh > /dev/null 2>&1

这样不会有任何输出被发送到邮箱,但你仍然可以在 ${SCRIPT_LOG} 中看到详细日志。


脚本优化与安全注意事项

细颗粒度优化

  • 按日期分目录存储:让你的日志系统每天生成独立的目录(如 logs/2025-01-15/),脚本就可以直接删除整个过期目录,效率翻倍
  • 保留最后N个文件:如果你不希望依据天数,而是想保留最近100个文件,可以使用 ls -1t | tail -n +101 配合 rm
  • 发送报警通知:当删除的文件数量超过阈值(比如一次删除了1000个文件),利用 mailcurl 发送告警给运维人员

安全红线(务必遵守)

  1. 永远先测试再上线:先在测试环境运行脚本,用 -print 代替 -exec rm 查看哪些文件会被删除
  2. 留意别的应用:确认目标目录中没有其他应用的重要数据文件(.dat, .json 等非日志文件)
  3. 尽量使用绝对路径:无论是目录、日志文件、脚本路径,都用绝对路径,避免 cron 的环境变量问题
  4. 小心符号链接find-type f 可以避免误删链接指向的外部文件

更专业的替代方案

如果你觉得手动维护脚本太麻烦,可以考虑以下企业级方案:

  • logrotate:Linux 自带的日志轮转工具,支持压缩、轮转天数、保留数量
  • ELK + Curator:在 Elasticsearch 端自动管理索引生命周期
  • 商业监控软件:如 Zabbix、Nagios 自带的日志清理功能

通过以上完整的学习,你已经掌握了从编写、测试到部署定时删除过期日志的脚本的全流程,无论是面对500G的日志洪流,还是遇到磁盘告警,这套方案都能让你成为“自动清理高手”,现在就动手在你的服务器上实践一下吧!

抱歉,评论功能暂时关闭!