CentOS shell如何获取昨天日期并打包日志?
服务器日志天天涨,磁盘报警比闹钟还准时。想自动把昨天的日志打包甩到备份目录,还要让文件名带上日期,手动改名字太掉价,一条shell命令就能解决,却总有人卡在“昨天日期怎么算”这一步。下面把最简方案直接甩出来,复制就能用,顺便把坑填平。

为什么非要“昨天”而不是“前天”
日志是按天切割,零点一过新文件生成,旧文件立刻停止写入。此时打包不会触发“文件被占用”的警告,压缩率也最高。若等到第三天再处理,中间可能又被日志清理脚本删了,哭都来不及。
获取昨天日期的三种写法
写法一:date -d 最常用
date -d "1 day ago" +%Y%m%d
输出形如 20240618,直接当字符串用。CentOS 7 默认 GNU date,-d 参数支持自然语言“1 day ago”,别写成“-1 day”,老版本会报错。

写法二:相对秒数计算
date -d @$(( $(date +%s) - 86400 )) +%Y%m%d
86400 是一天的秒数,适合写脚本里,避免不同语言环境把“day ago”翻译成“日前”导致失败。
写法三:纯busybox环境
某些极简容器只有 busybox,date 不支持 -d,用 awk 硬算:
awk 'BEGIN{print strftime("%Y%m%d", systime()-86400)}'

三选一即可,别混用,保持脚本风格统一。
一条命令打包昨天日志
假设日志放在 /var/log/nginx,每天生成 access.log 和 error.log,零点切割后变成 access.log-20240618 这种后缀。想把昨天的俩文件一起压成 gzip,并放到 /backup/nginx,命令如下:
yesterday=$(date -d "1 day ago" +%Y%m%d) && tar -czf /backup/nginx/nginx-${yesterday}.tar.gz -C /var/log/nginx $(ls /var/log/nginx/*-${yesterday} 2>/dev/null)
解释:
1. yesterday 变量先算好,后面多处引用,避免多次执行 date 命令。
2. tar 的 -C 参数切换目录,打包时文件路径不带长目录,解压更干净。
3. ls 后面跟通配符,只匹配昨天后缀的文件,2>/dev/null 防止空列表报错。
4. 如果日志命名规则是 .log.20240618,把通配符改成 *.log.${yesterday} 即可。
整点自动跑,交给 crontab
每天两点十分执行,避开日志切割时间:
10 2 * /bin/bash /opt/scripts/packnginxlog.sh >/dev/null 2>&1
脚本内容拆出来,方便调试:
#!/bin/bashbackup_dir="/backup/nginx"
log_dir="/var/log/nginx"
yesterday=$(date -d "1 day ago" +%Y%m%d)
mkdir -p "$backup_dir"
files=$(ls $log_dir/*-${yesterday} 2>/dev/null)
if [ -n "$files" ]; then
tar -czf "$backupdir/nginx-${yesterday}.tar.gz" -C "$logdir" $files
fi
加完权限 chmod +x,丢到 /opt/scripts,crontab 直接调。
多目录循环打包,一个 for 全搞定
系统里除了 nginx,还有 tomcat、php-fpm,目录不同,命名规则却一样,用 for 循环最省事:
yesterday=$(date -d "1 day ago" +%Y%m%d)for app in nginx tomcat php-fpm; do
log_dir="/var/log/$app"
backup_dir="/backup/$app"
mkdir -p "$backup_dir"
files=$(ls $log_dir/*-${yesterday} 2>/dev/null)
[ -n "$files" ] && tar -czf "$backupdir/${app}-${yesterday}.tar.gz" -C "$logdir" $files
done
新增应用只要在 for 里加空格隔开,脚本零改动。
打包后顺手删旧备份,只留七天
磁盘再大也扛不住只写不删,find 一行清掉七天前的包:
find /backup -name "*.tar.gz" -mtime +7 -delete
加到脚本末尾,打包完成立即执行,避免另起定时任务忘记配。
文件名想带横杠或下划线?改格式串
有人习惯 2024-06-18,把 +%Y%m%d 换成 +%F 即可;想要 20240618 就写 +%Y%m%d。格式串一次到位,后面所有脚本统一,别今天横杠明天下划线,自己给自己埋雷。
打包失败如何告警
tar 返回非零代表失败,脚本里捕捉 exit code,发邮件或调钉钉机器人:
tar -czf "$backupdir/nginx-${yesterday}.tar.gz" -C "$logdir" $files
if [ $? -ne 0 ]; then
echo "打包失败:nginx ${yesterday}" | mail -s "日志备份告警" admin@example.com
fi
邮件服务没装,用 curl 调群机器人一样行,只要 exit code 判断准,告警就不会漏。
常见翻车点速查
1. 日期变量没引号,文件名带空格直接炸。
2. 系统语言是中文,date -d “1 day ago” 被本地化翻译失败,提前 export LC_ALL=C。
3. 日志切割脚本和打包脚本同时跑,tar 刚好读到被重命名的半拉文件,加锁文件或错开五分钟。
4. 备份目录没写权限,tar 创建文件失败,却忘了看错误输出,以为命令无效。
5. 手动测试成功,crontab 里失败,八成是没写绝对路径,tar、date、ls 全写 /bin/date 最保险。
小结
CentOS 下拿昨天日期就是 date -d “1 day ago” 一句话,配合 tar 通配符打包,十分钟写完脚本,丢进 crontab 就能躺平。变量引号、路径权限、错误码判断三步到位,再也不怕磁盘爆满。脚本越短,坑越少,跑稳了才是硬道理。
