最稳妥方案是用 find + -mtime,但需确认备份文件 Modify 时间可信;-mtime 反映内容写入完成时间,比易变的 -ctime 和不可靠的文件名日期更准确。

直接用 find + -mtime 是最稳妥的方案,但必须确认备份文件的 Modify 时间可信;否则会误删或漏删。
为什么必须用 -mtime 而不是 -ctime 或文件名日期
-mtime 反映的是文件内容最后一次写入完成的时间,在多数规范备份流程中(如 mysqldump > backup.sql、mysqldump | gzip > backup.sql.gz),这个时间基本等同于备份生成时刻。而 -ctime 是元数据变更时间,chown、chmod、甚至 mv 都会触发它,极易失真。文件名里的日期(如 backup_20260401.sql.gz)看着直观,但一旦文件被移动、重命名、解压再压缩,就完全不可靠。
验证方式很简单:stat backup_20260401.sql.gz 看输出中的 Modify: 行,别只信 ls -l 的简略显示。
find -mtime +7 的真实含义和常见误解
-mtime +7 不是“超过 7 个日历天”,而是“修改时间距今 ≥ 7 × 86400 秒”,且按整天向下取整。也就是说:
-
-mtime 0→ 修改发生在最近 24 小时内(0 ~ 24 小时前) -
-mtime +7→ 修改发生在 7 天前的 00:00:00 之前(即 ≥ 168 小时) - 如果某备份是今天凌晨 2 点生成的,那它要到后天凌晨 2 点才满足
-mtime +1
所以如果你希望“保留最近 7 天的备份”,应使用 -mtime +6(即删掉 7 天前及更早的),而非 +7。生产脚本里写错这个数,会导致多留一天冗余。
放进 crontab 前必须处理的三件事
直接把本地测试好的 find 命令粘进 crontab,90% 会失败。原因很实际:
- 不带绝对路径:
find在 cron 默认环境里可能找不到,得写成/usr/bin/find - 工作目录不确定:cron 不自动
cd到你的备份目录,路径必须写死,不能用~/backup或相对路径 - 没捕获错误:删失败了你根本不知道,得加日志重定向,例如
>> /var/log/clean-backup.log 2>&1
推荐 crontab 条目写法:0 3 * * * cd /data/backup/mysql && /usr/bin/find . -type f -name "*.sql.gz" -mtime +6 -delete >> /var/log/clean-backup.log 2>&1
当 -mtime 不可靠时,改用文件名日期解析
典型场景:备份脚本用 rsync 同步旧备份、或用 cp --preserve=timestamps 复制,导致目标文件 mtime 被覆盖为复制时刻;或者备份目录混有手动上传、解压再打包的文件。
这时就得放弃 -mtime,改从文件名提取日期判断。例如命名是 full_backup_20260401_0200.sql.gz:
find /data/backup/mysql -name "full_backup_*.sql.gz" -exec basename {} \; | \
awk -F'_' '{datestr=$2; gsub(/\.sql\.gz/, "", datestr); if (datestr < strftime("%Y%m%d", systime() - 7*24*3600)) print $0}' | \
xargs -r rm更健壮的做法是把这类逻辑封装进备份脚本本身:每次生成新备份后,立刻执行 find /data/backup/mysql -name "full_backup_$(date -d '7 days ago' +%Y%m%d)*.sql.gz" -delete —— 这样时间源唯一,且避免跨时区、夏令时等问题。
真正容易出问题的不是命令怎么写,而是默认相信 ls -l 看到的时间,或者在没验证 stat 输出的情况下,就把 -mtime +7 直接塞进生产 crontab。


















