find的使用方法和典型使用场景
1.磁盘占用过高问题定位
最近在学习一些关于服务器磁盘方面的运维知识,正好发现我的一台机器上根目录磁盘占用达到了96%,这个占用量已经非常危险了
首先使用 df -h 查看磁盘占用率:
文件系统 大小 已用 可用 已用% 挂载点
tmpfs 1.6G 2.8M 1.6G 1% /run
/dev/nvme0n1p4 57G 52G 2.3G 96% /
tmpfs 7.7G 0 7.7G 0% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
/dev/nvme0n1p2 1.9G 287M 1.5G 17% /boot
/dev/nvme0n1p5 27G 7.8G 18G 31% /home
/dev/sda 916G 229G 641G 27% /data
接下来结合最近学习的内容,来说一说解决思路和方案。
新手的最常见的做法往往是 cd 进各个目录,挨个 du -sh * ,一层一层翻下去,运气不好就能翻很长时间,最后也找不到占用磁盘的大文件到底在哪里。
而真正熟悉 find 的人,只会敲一行:
find / -xdev -type f -size +500M 2>/dev/null
等待片刻后,所有超过500MB的大文件全部列出来,占用磁盘的元凶一目了然。
除了磁盘占用高的故障,find 还有很多日常运维工作中排障用法。
2.find到底做了什么
find 的核心逻辑非常简单:从某个目录开始,遍历它和它所有子目录中的每一个文件和目录,按你给的条件挑出符合条件的部分。
基本语法:
find <路径> <条件>
比如:
find /var/log -name "*.log"
意思是:从 /var/log 开始,递归查找所有文件名以 .log 结尾的文件。如果不写任何动作,GNU find 默认会执行 -print ,也就是把结果打印出来。所以其实大多数人都在用省略 -print 的简化写法。
这个过滤功能看起来和 grep 有点像,但本质完全不同:grep 搜的是文件内容,find 搜的是文件本身(文件名、类型、大小、时间、权限、归属)。所以在排障时经常会见到 find 和 grep 配合使用。
3.find核心能力
-
按文件名查找:
-name / -inamefind /etc -name "*.conf" find /etc -iname "*.CONF"-name区分大小写,-iname不区分大小写(ignore)。这里再补充两个高频写法:
排除某种文件,用
!(逻辑非):find . -name "*test*" ! -name "*.log"意思是:找出文件名包含
test的文件,但排除掉.log结尾的文件。很多人在使用过程中会忽略find本身的排除功能。但是这里需要注意一点,一个!只能管它后面的1个条件,如果还需要一个排除条件,就需要多一个!。 -
按文件类型查找:
-type只找目录:
find /opt -type d只找普通文件:
find /opt -type f只找符号链接:
find /opt -type l排障时经常要确认一个文件到底是目录还是文件还是软链接,
-type直接筛查干净。 -
按时间查找:
-mtime / -mmin这是日常运维中用得最多的条件之一。
find /var/log -name "*.log" -mtime +7意思是:找出
/var/log下,最后修改时间超过7天的日志文件。这里有个细节要注意:+7表示超过七天,-7表示7天以内,不带符号的7表示刚好第7天。日常用的比较多的是+n,用来清理过期日志find /var/log -name "*.log" -mtime +7 | xargs rm如果要按照分钟算,比如排查最近10min被改动过的文件:
find /etc -mmin -10 -
按大小找:
-sizefind / -xdev -type f -size +500M+500M表示大于500MB,-size同样支持+ -表示大于、小于。这里顺便说一下-xdev:它的作用是只在当前文件系统内搜索,不跨到其它挂载点。如果从/开始搜索却不加-xdev,find会一路钻进/proc、/sys这些虚拟文件系统,不仅慢,还会出一堆没有意义的结果,外加大量权限不足的报错。可以在命令后面加上2>/dev/null把错误信息丢掉,只看正常结果:find / -type f -size +500M 2>/dev/null如果不光想知道有哪些大文件,还想按大小排序,列出占用最多空间的几个,可以配合
-exec du和sort:find / -xdev -type f -size +100M -exec du -h {} \; 2>/dev/null | sort -rhdu -h {}把每个匹配文件的实际大小算出来,sort -rh按人类可读的大小做降序排列,这样输出的就是从大到小排好序的列表,比单纯列文件名更直观。 -
按权限找:
-permfind / -perm -4000 -type f 2>/dev/null据说这个命令是一条经典的安全审计命令,用来找出所有设置了SUID权限位的文件,这类文件执行时会临时获得文件所有者(通常是root)的权限,如果被恶意利用,就是一个常见的权限提升突破口,所以安全排查、入侵检查时经常用到这条命令。
-
对找到的结果执行命令:
-exec这是
find命令最强大的能力,找到文件之后,直接对它们执行命令,不用再手动复制粘贴文件名:find /var/log -name "*.log" -mtime +30 -exec rm {} \;{}是占位符,代表当前匹配到的文件;结尾的\;表示每找到一个文件,就单独执行一次命令,这种写法的问题是:如果匹配到了1000个文件,就会启动1000次的rm进程,效率比较低。更高效的写法是用+结尾:find /var/log -name "*.log" -mtime +30 -exec rm {} ++会把尽可能多的文件名打包,合并成尽量少的命令调用次数,效果上更接近xargs的批处理方式,速度明显更快。find /var/log -name "*.log" -mtime +30 | xargs rm这里建议任何带
-exec rm或者-delete的命令,第一次执行前,先把删除动作换成-print,确实列出的文件都是需要删除的,然后再加删除动作,可以避免在排障过程中又制造故障 。find /var/log -name "*.log" -mtime +30 -print-exec还有一个很常见的组合用法,就是配合grep一起用,相当于把找文件和找内容链接到一起:find . -name "*.cc" -exec grep -l "void main" {} \;意思是,先用
find把所有.cc文件找出来,再对每一个文件用grep看里面是否包含void main这段代码。这也就是为什么find和grep是最常见的搭档关系,一个负责定位文件范围,一个负责定位内容。 -
内置删除:
-deletefind /tmp -name "*.tmp" -mtime +1 -delete-delete是find自带的删除动作,效果类似-exec rm {} \;,但执行效率更高,不需要额外启动rm进程。执行同样需要注意安全,建议先不带操作跑一遍,合适后再执行删除。 -
排除某些目录:
-prune排障或者搜代码的时候,经常不想搜进
.git、node_modules这种目录,用prune可以直接跳过:find . -path "./node_modules" -prune -o -name "*.js" -print拆解一下这条命令,
-path "./node_modules" -prune表示如果路径匹配到node_modules就不要继续往下钻;后面的-o -name "*.js" -print表示,否则的话,按照规则*.js匹配并打印。-o表示两个互斥的条件,配合-prune实现跳过某个目录,但正常处理其他部分的效果。 -
配合
xargs使用find . -name "*.bak" -print0 | xargs -0 rm直接用
find ... | xargs rm在文件名包含空格或特殊字符时会出错,因为xargs默认按空白符切割参数。-print0会让find用\0而不是换行符分隔文件名,配合xargs -0使用,可以安全处理任何带空格、换行的奇葩文件名,这是处理批量文件操作时的标准安全写法。
4.性能优化:为什么有时候 find 会让服务器卡住
find 是实时遍历文件系统,目录越深、文件越多,扫一遍花的时间就越长。这里有两个真实场景:
场景1:定时任务里的 find 拖垮了服务器
有的公司会在 crontab 中设置定时清理任务,每天清理 /tmp 下一天前产生的大量临时文件,结果每次任务一跑,服务器负载会跟着飙升,影响其他服务。原因就是 find 要遍历的文件数量太大,加上后面如果又配合了低效的 -exec ... \; 逐个删除,进程开销叠加在一起对系统的瞬时压力很明显。
优化思路也比较直接:
find /tmp -maxdepth 1 -type f -mtime +1 -delete
-maxdepth 1 限制只搜索第一层目录,不再往更深的子目录钻。因为很多场景下,其实不需要无限递归,使用这个限制可以大幅度减少要扫描的文件数量;同时把删除动作换成内置的 -delete ,而不是逐个调用外部的 rm ,进一步降低开销。
场景2: 从根目录搜索时,意外扫到了网络文件系统
如果服务器挂载了 NFS(网络文件系统),从 / 开始的 find 默认会一路扫进这些网络挂载点,而网络文件系统的访问速度通常远低于本地磁盘,一旦扫进去,耗时会成倍增加。这种情况下,前面提到的 -xdev 同样能帮上忙——它不仅能跳过 /proc、/sys,也能避免跨到其他挂载的文件系统(包括网络存储)。
对于一个数据量很大的目录来跑 find ,如果不急着要结果,可以加 & 放后台执行,避免占着终端干等。
5.一个真实的排障过程:磁盘爆满复盘
第一步,找出根分区下的大文件
find / -xdev -type f -size +500M 2>/dev/null
发现以下文件:
/root/.cache/pip/http-v2/5/5/6/4/a/5564a871319d42ec90c363f7100f58767ded8bcadf47ba562e43ec00.body
/var/lib/snapd/cache/bece47eaffcab46af8b7ec79322cdf6d6aa8f3ffaaa5b1f51e4dcec1333e33b6840775d7fbc4736d74ddfcbec1e8d58a
/var/lib/snapd/cache/0e99938fd412cec5852ed680bcbc536e1929ff31315a57224aa7cb03867f2505bada1452bcbe1ac6c9f2e35101c4612f
/var/lib/snapd/cache/2b4539cb4dfdb33019d64567982948db646776d113d2df5424dcf6fe9badc91d5cff61e88c01c8a01e53a5925b2def54
/var/lib/snapd/cache/6b8f0b8920d12519d7c5e677950a231810fa253e34962f312b3dfa58af9d91eeab9d5c1b3483cf0da6df66f23f3f5f8d
/var/lib/snapd/snaps/gnome-42-2204_247.snap
/var/lib/snapd/snaps/gnome-46-2404_164.snap
/var/lib/snapd/snaps/gnome-46-2404_153.snap
/var/lib/snapd/snaps/gnome-42-2204_263.snap
第二步,确认这些文件是不是真的没用了
find /var/lib/snapd -type f -mtime +30 2>/dev/null
加上 -mtime +30,确认这些大文件已经 30 天没被修改过,基本可以判断是历史遗留的无用文件,而不是正在使用的数据。
第三步,先打印确认,然后再 -delete
find /var/lib/snapd -type f -mtime +30 2>/dev/null
find /var/lib/snapd -type f -mtime +30 -delete
第四步,检查磁盘空间是否恢复
df -h /
整个过程没有手动进任何一个目录,全程靠 find 的条件组合完成定位、确认、清理三个阶段——这正是它被低估的地方:大家都知道它能”找文件”,但很少有人把它当成一个完整的排障加处理工具来用。
6.踩坑总结
- 忘记给通配符加引号:
find . -name *.txt几乎一定会出问题,一定记得是find . -name "*.txt" - 从根目录搜索不加
-xdev,会一路钻进/proc、/sys,甚至跨到网络挂载的文件系统,慢且没意义,所以记得加上-xdev,同时用2>/dev/null屏蔽权限报错。 - 把
-ctime当成创建时间,-ctime是元数据变更时间,不是创建时间,这是一个普遍的误区。 - 直接执行
-delete或-exec rm,不先-print确认,linux中删除是一个不可逆操作,所以一定要先打印结果确认,再补上删除动作,啥急事也急不了这几分钟,养成这个结果可以避免很多事故。 - 用
-exec ... {} \;处理大批量文件,会逐个启动rm进程,效率很低, 能用-exec ... {} +或者配合xargs就尽量用。 - 大范围搜索不加
-maxdepth,明明只需要搜第一层目录,却让find递归深钻,纯属浪费时光。
7.运维专业的高频面试题,感受一下
服务器上有一个 .logs 目录,如何删除该目录下最后一次访问时间超过1年的文件?
find .logs -type f -atime +365 -print
find .logs -type f -atime +365 -exec rm {} +
find .logs -type f -atime +365 -delete
这道题同时考察了3个知识点,-type 区分文件和目录、-atime 来按访问时间筛选结果、-print 确认结果后再删除的安全习惯。
8.写在最后
很多服务器是不提供图形界面的,就算有界面,如果不提供 FTP服务的话,那么关于文件系统的所有访问都只能在终端里进行。以前刚接触这一块的时候,找文件都是 cd + ls 古法查找,慢慢熟练的以后,就算知道有 find 这么个工具,也是用得不多。但是随着接触的业务量级越来越大,动辄就是上百G、几个T的文件,这时候再用老办法基本是完成不了工作的,所以还是得与时俱进。
而且技术手段这东西更新太快,现在不学会 find ,说不定又会被新的工具取代,每次一学新技术,就发现自己落后好几个版本,这可是要出大问题的。