Shell脚本如何压缩归档历史日志

wen 实用脚本 1

Shell脚本如何压缩归档历史日志:自动化日志管理的完整指南

目录导读

  1. 为什么需要压缩归档历史日志?
  2. Shell脚本基础与核心命令解析
  3. 实战:编写高效的日志压缩归档脚本
  4. 自动化调度与Crontab配置
  5. 常见问题与最佳实践(含问答)

为什么需要压缩归档历史日志?

在服务器运维中,日志文件以GB级速度增长,若不及时处理,会占用磁盘空间、拖慢I/O性能,甚至导致系统崩溃。压缩归档能将历史日志体积减少70%-90%,同时按日期或大小切割文件,便于后续检索与合规审计,Shell脚本因轻量、无依赖、跨平台,成为运维人员首选的自动化工具。

Shell脚本如何压缩归档历史日志

核心痛点

  • 磁盘告警常由未归档日志引发
  • 手动操作耗时且易遗漏
  • 缺失归档策略导致日志覆盖或被误删

Shell脚本基础与核心命令解析

编写日志归档脚本前,需掌握以下命令:

命令 作用 典型参数
tar 打包与压缩 -czf(gzip压缩)、-jcf(bzip2压缩)、--remove-files(压缩后删除源文件)
gzip / bzip2 单文件压缩 -9(最大压缩率)、-d(解压)
find 文件查找 -name(通配符)、-mtime +30(修改时间超30天)、-size +100M
awk 文本处理 提取日期、切割文件名
date 日期格式化 +%Y%m%d+%Y-%m-%d
mv / rm 移动与删除 -f(强制)、-v(显示过程)

关键设计思想:脚本应具备可配置性(路径、保留天数、压缩方式)、健壮性(异常处理、空目录跳过)、可追溯性(生成日志记录)。


实战:编写高效的日志压缩归档脚本

以下是一个经过企业级验证的脚本模板,综合了搜索引擎中多篇高质量文章的最佳实践:

#!/bin/bash
# ==========================================
# 历史日志压缩归档脚本 v2.3
# 功能:按日期归档旧日志,保留最近N天,压缩后删除源文件
# 适用:Nginx、Tomcat、应用程序日志
# ==========================================
# 配置区(可根据实际修改)
LOG_DIR="/var/log/app"
ARCHIVE_DIR="/data/archive/logs"
RETENTION_DAYS=30
COMPRESS_EXT=".tar.gz"
LOG_FILE="/var/log/archive_script.log"
# 日期戳
DATE_STAMP=$(date +%Y%m%d_%H%M%S)
ARCHIVE_NAME="app_logs_${DATE_STAMP}${COMPRESS_EXT}"
# 初始化日志函数
log_info() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: $1" >> ${LOG_FILE}
}
# 查找需归档的日志(假设日志按日期命名,如 access_20250301.log)
find_old_logs() {
    find ${LOG_DIR} -type f -name "*.log" -mtime +${RETENTION_DAYS} -print
}
# 核心归档逻辑
archive_logs() {
    local old_logs=$(find_old_logs)
    if [ -z "$old_logs" ]; then
        log_info "没有找到超过${RETENTION_DAYS}天的日志,跳过归档"
        exit 0
    fi
    # 创建临时文件列表,避免参数过长
    echo "$old_logs" > /tmp/archive_filelist_$$.txt
    # 打包压缩(使用--remove-files自动删除源文件)
    tar -czf ${ARCHIVE_DIR}/${ARCHIVE_NAME} \
        --files-from /tmp/archive_filelist_$$.txt \
        --remove-files \
        --transform 's|.*/||'  # 去除绝对路径,仅保留文件名
    if [ $? -eq 0 ]; then
        log_info "成功归档${ARCHIVE_NAME},共压缩$(wc -l < /tmp/archive_filelist_$$.txt)个文件"
    else
        log_info "归档失败,请检查磁盘空间或权限"
        exit 1
    fi
    # 清理临时文件
    rm -f /tmp/archive_filelist_$$.txt
}
# 设置脚本锁,防止并发执行(重要!)
LOCK_FILE="/var/run/archive_logs.lock"
if [ -e ${LOCK_FILE} ] && kill -0 $(cat ${LOCK_FILE}) 2>/dev/null; then
    log_info "脚本已在运行,退出"
    exit 1
fi
echo $$ > ${LOCK_FILE}
trap "rm -f ${LOCK_FILE}" EXIT
# 执行主函数
archive_logs
# 可选:删除过期的归档文件(如保留30天的归档包)
find ${ARCHIVE_DIR} -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete
log_info "已清理超过${RETENTION_DAYS}天的归档包"

脚本亮点说明

  • 并发锁:防止cron多次执行导致文件混乱
  • 临时文件列表:解决find输出过大时的Argument list too long错误
  • --transform:确保压缩包内结构扁平,解压时不覆盖同名文件
  • 双删除策略:源日志压缩后删除,过期归档包独立清理

自动化调度与Crontab配置

将脚本部署到/usr/local/bin/archive_logs.sh,添加执行权限:

chmod +x /usr/local/bin/archive_logs.sh

设置crontab每天凌晨执行(避免高峰时段影响I/O):

0 2 * * * /bin/bash /usr/local/bin/archive_logs.sh

进阶调度策略(根据日志生成速度调整):

  • 每日执行:适用于大部分场景
  • 每小时执行:适用于高频写入日志(如每秒数万请求的Web服务器)
  • 配合logrotate使用:logrotate处理切割,脚本处理压缩归档

常见问题与最佳实践(含问答)

Q1:压缩后源文件被删除,如何验证数据完整性?

A:在tar命令前添加tar -tvf验证压缩包内容。

tar -tvf ${ARCHIVE_DIR}/${ARCHIVE_NAME} > /tmp/verify_$$.txt

确保文件数匹配,企业级方案可加入MD5校验。

Q2:日志文件名不规则(如包含空格或特殊字符),如何处理?

A:使用find-print0配合xargs -0,或直接写入临时文件(如脚本所示),避免使用for循环解析find输出。

Q3:磁盘空间已满,脚本执行失败怎么办?

A:在脚本头部添加磁盘检查:

DISK_USAGE=$(df ${ARCHIVE_DIR} | awk 'NR==2 {print $5}' | sed 's/%//')
if [ ${DISK_USAGE} -gt 90 ]; then
    log_info "磁盘使用率超过90%,跳过归档"
    exit 1
fi

同时建议归档到独立挂载点或NAS存储。

Q4:如何实现按文件大小而非时间归档?

A:将find-mtime +N替换为-size +100M(大于100MB),组合使用:

find ${LOG_DIR} -type f -name "*.log" \( -mtime +7 -o -size +500M \)
  1. 每日第一件事:检查archive_script.log是否正常执行
  2. 保留策略:日志源保留7-30天,归档包保留3-6个月
  3. 权限最小化:脚本只用root或loguser运行
  4. 测试先行:先在测试环境用--dry-run模拟(移除--remove-files
  5. 监控告警:若归档失败,通过cron发送邮件或对接监控系统

推荐扩展阅读:结合logrotatesharedscripts参数,实现日志切割与归档的一体化方案。


通过以上步骤,你将拥有一个生产可用的Shell日志归档脚本,它不仅压缩了空间,更压住了运维焦虑——毕竟,自动化是消除重复劳动的最优雅方式

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