用 find 批量删日志前,先用 -print 确认范围
服务器磁盘写满,第一反应往往是清日志。典型场景是 /var/log 或某个应用目录下堆了成千上万个 .log 文件,只想删掉七天前的那些。这时 find 是最顺手的工具,但 -delete 一旦配上写错的条件,删掉的就是不该删的东西。
先跑一遍看清单
结论:把 -delete 换成 -print,先看它打算删哪些文件。
find . -name '*.log' -mtime +7 -print
这行在做什么:在当前目录及子目录里,找出名字以 .log 结尾、最后修改时间超过 7 天的文件,并把路径打印出来。它只读不写,没有任何副作用。
确认输出范围和预期一致后,再把 -print 换成 -delete:
find . -name '*.log' -mtime +7 -delete
这行在做什么:同样的条件,但把命中的文件直接删除。注意 -delete 必须放在表达式末尾,放前面会报错。
为什么先 -print 有效
find 的表达式是从左到右求值的。-print 和 -delete 都是“动作”,命中一个文件就执行一次。把动作换成打印,等于让 find 把它的判断结果原样告诉你。
误删通常来自条件本身写错,而不是 -delete 有问题。常见几类:
-mtime +7的含义是“修改时间大于 7 个 24 小时”,第 8 天才算命中,不是“7 天前的那一刻”。想按天精确,用-mtime +7前先看-print的日期是否符合预期。-name '*.log'只匹配文件名,不匹配路径。如果目录里还有app.log.1、error.log.gz,它们不会被命中,别以为清干净了。- 忘了加
-type f,目录名恰好以.log结尾时也会被算进去。
这些问题在 -print 的输出里一眼能看出来,在 -delete 之后就只能靠备份了。
怎么确认删对了
删除前,把输出重定向到文件留个底:
find . -name '*.log' -mtime +7 -print > /tmp/to-delete.txt
wc -l /tmp/to-delete.txt
第一行把待删清单存下来,第二行数一下有多少条。数字和预期差一个量级,就说明条件写错了,先别删。
删除后再跑一次同样的 -print,输出应该为空。不为空说明还有残留,或者条件没覆盖到。
边界和坑
-delete 不会进回收站,删了就是删了。对系统日志目录操作前,确认没有服务正在写这些文件;正在被写入的日志删掉后,进程仍持有文件句柄,磁盘空间不会立刻释放,要重启对应服务或等它重新打开文件。
-delete 隐含了 -depth,也就是先处理子目录再处理父目录。这和手动 -print 再 xargs rm 的行为不同,混用两种写法时结果可能不一致。
另外,-mtime 按文件修改时间算,不按访问时间。如果日志被轮转工具改过名或 touch 过,时间判断会失准,这种情况更适合按文件名里的日期字段匹配,而不是靠 -mtime。
最后一条:在 / 或家目录这类大范围路径上跑 find 前,务必先 -print 并限制深度,比如加 -maxdepth 3,否则一次遍历可能跑很久,输出也难核对。