服务器磁盘写满,第一反应往往是清日志。典型场景是 /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,否则一次遍历可能跑很久,输出也难核对。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注