-mtime +7 实际删除修改时间≤2026年5月1日00:00:00的文件,因按整24小时向下取整,故保留的是最近6天而非7天;正确保留7天应使用-mtime +6,并配合-type f、-name过滤及-maxdepth 1确保安全。

用 find -mtime 清理 MySQL 备份最常用,但直接写 -mtime +7 很可能删多或删少——关键在理解它算的是“整 24 小时段”,不是日历天数。
为什么 -mtime +7 不等于“保留最近 7 天”
今天是 2026年5月8日 16:20,-mtime +7 实际清理的是“最后修改时间 ≤ 2026年5月1日 00:00:00”的文件,而非 5月1日当天生成的全部文件。因为 -mtime 按完整 24 小时向下取整:
-
-mtime 0:过去 24 小时内(即 5月7日 16:20 之后) -
-mtime +6:修改时间 ≤ 5月1日 00:00:00 → 这才是“保留最近 7 天”的正确写法 -
-mtime +7:实际删的是 ≥ 8 天前的文件,相当于只留 6 天
若备份脚本在每天凌晨 2 点执行,那 5月1日 02:00 生成的文件,要到 5月9日 02:00 才满足 -mtime +7 ——中间有近 22 小时误差。
必须加 -type f 和精确 -name 过滤
备份目录里常混着临时文件、锁、日志甚至子目录,不加限制的 find /backup -mtime +6 -delete 可能误删正在写的 .part 文件或 mysql-bin.000001 二进制日志。
- 只操作普通文件:
-type f - 限定扩展名组合:
-name "*.sql.gz" -o -name "*.xbstream" -o -name "*.zst" - 排除临时文件:
! -name "*.part" ! -name "*.tmp" - 防止钻进子目录:
-maxdepth 1
完整安全命令示例:find /backup/mysql -maxdepth 1 -type f \( -name "*.sql.gz" -o -name "*.xbstream" \) ! -name "*.part" -mtime +6 -print
务必先用 -print 看结果,确认无误再换 -delete。
当备份命名含日期时,优先按文件名清理更可靠
如果备份文件名类似 db_prod_20260501_0200.sql.gz,而你又用 rsync 同步过或手动 touch 过,-mtime 就不可信了——文件内容没变,但时间戳被覆盖了。
- 用
date -d "7 days ago" +%Y%m%d生成阈值日期(如 20260501) - 用
find ... -exec sh -c '[[ $(basename "$1") =~ _([0-9]{8})_ ]] && [[ ${BASH_REMATCH[1]} -lt 20260501 ]] && rm "$1"' _ {} \; - 这种匹配绕开了文件系统时间,只认名字里的日期,适合对一致性要求高的生产环境
crontab 中执行 find 必须显式设置 PATH 和重定向错误
root 的 crontab 默认 PATH 很窄,find 可能找不到,-delete 在旧版 find(如 CentOS 6)里也不支持。
- 在 crontab 里写全路径:
/usr/bin/find /backup ... -exec /bin/rm {} \; - 显式声明 PATH:
PATH=/usr/local/bin:/usr/bin:/bin - 始终重定向 stderr:
2>>/var/log/cleanup.log,否则失败无声无息 - 避免并发冲突:如果备份脚本和清理脚本都写同一目录,加简单锁文件或错开执行时间(如备份在 02:00,清理在 02:15)
真正容易被忽略的不是语法,而是时间语义和并发场景——-mtime +N 看似简单,但跨午夜、跨时区、跨同步操作后,它的行为就和直觉不一致了。文件名日期匹配虽稍重,但在关键业务里反而更省心。











