find 命令详解
更新时间:2026-08-29。本文是「一个命令一个文档」系列,属于文件查找命令。当你问"哪个文件 7 天前改过""tmp 里大于 100M 的是谁",
find是标准答案。
为什么写 find?因为它和 ls、grep 并称日常三件套,但选项最杂、最容易被"查不到"。新手常把 -name 和 shell 通配符搞混(find 里的 * 必须引号包住,否则被 shell 先展开)。理清 -name/-type/-mtime/-size/-exec 这五个,九成查找需求通吃。
find 从指定路径递归遍历目录树,对每个匹配条件的文件执行动作(默认打印路径)。
一、最基本的用法
find . -name "*.log" # 当前目录递归找所有 .log
find /etc -name "passwd" # 在 /etc 里找名为 passwd 的文件
find ~ -type f # 家目录下所有普通文件(不含目录)关键陷阱:
find . -name *.log不加引号,shell 会先把*.log展开成当前目录的匹配项再传给 find,结果完全不对。find的 pattern 一定要用引号包住,让 find 自己去做通配。
二、高频选项一张表
| 选项 | 作用 | 示例 |
|---|---|---|
-name | 按文件名(支持 * ? []) | find . -name "*.cpp" |
-iname | 同上但忽略大小写 | find . -iname "readme*" |
-type | 按类型:f文件 d目录 l链接 | find . -type d |
-size | 按大小:+100M大于 -10k小于 | find . -size +100M |
-mtime | 按修改时间(天):-7 7天内 | find . -mtime -7 |
-atime / -ctime | 访问时间 / 状态变更时间 | find . -atime +30 |
-user / -group | 按属主/属组 | find / -user root |
-perm | 按权限位 | find . -perm 777 |
-maxdepth | 限制递归深度 | find . -maxdepth 1 -name "*.tmp" |
-path / -prune | 排除某路径 | find . -path ./node_modules -prune -o -name "*.js" |
-newer | 比某文件更新的 | find . -newer ref.txt |
-mtime -7是"7 天内",+7是"7 天前",-mtime 0是"24 小时内"。数字游戏容易晕,记口诀:减号=之内,加号=之前。
三、时间戳三兄弟:atime / mtime / ctime
find 的 -atime/-mtime/-ctime 常被混淆:
- mtime(modify):内容被修改的时间——最常用,比如"找昨天改过的代码"。
- atime(access):被读取的时间——cat 一下就更新,但很多系统为性能默认不更新 atime(挂载
relatime),所以 atime 不可靠。 - ctime(change time):元数据变更时间(权限/属主/重命名),不是创建时间!Linux 没有文件创建时间字段(btrfs/zfs 有,但 find 不查)。
stat file.txt # 三时间都显示,配合理解,见 stat四、实战 demo
demo 1:找出 7 天内改过的所有源码
find . -name "*.py" -mtime -7
# 定位近期动过的 Python 文件,代码审查/打包前常用demo 2:揪出占用空间的罪魁(大于 100M)
find / -type f -size +100M 2>/dev/null
# 2>/dev/null 屏蔽"权限不足"的报错噪音
# 全盘找大文件,定位磁盘爆满元凶demo 3:删掉 30 天前的临时文件(安全范式)
find /tmp -type f -mtime +30 -delete
# -delete 直接删;稳妥做法先 -print 看匹配,确认再换 -delete
# 或 find /tmp -type f -mtime +30 -exec rm {} \;demo 4:找到文件后对每一个执行命令(-exec)
find . -name "*.bak" -exec rm -i {} \;
# {} 是占位符,\; 表示 -exec 结束(每条文件启动一次 rm)
# 想一次传多个文件提速:find ... -exec rm -i {} +demo 5:配合 xargs 做批量处理(大量文件更快)
find . -name "*.log" -mtime +7 | xargs rm
# 比 -exec 少启动进程;文件名含空格时用:
find . -name "*.log" -print0 | xargs -0 rmdemo 6:排除目录(不进 node_modules 找)
find . -path ./node_modules -prune -o -name "*.js" -print
# -prune 剪掉该分支;结构固定:prune -o (条件) -print五、和 grep / locate 的分工
- 找内容里的字串 → grep(或
grep -r/rg)。 - 找文件名且要实时精确 →
find(慢但准,遍历磁盘)。 - 找文件名且要快、可接受略旧索引 → locate(查 mlocate 数据库,秒回但非实时)。
grep -r "TODO" . # 找内容含 TODO 的文件
find . -name "*.todo" # 找名字叫 .todo 的文件
locate nginx.conf # 秒级按名定位(依赖 updatedb)六、常见坑
*必须引号包住,否则被 shell 展开。-mtime单位是天(24h),要按分钟用-mmin(如-mmin -60一小时内)。-size +100M的M是 1048576 字节;k/M/G大小写敏感。- 大量文件时
-exec ... {} \;每个文件启进程很慢,改用{} +或管道 xargs。 - 根目录
find /会报大量权限错误,加2>/dev/null屏蔽。
七、进阶:构建"找出来就处理"的流水线
find 的真正威力在于"找到 → 处理"一气呵成。下面三招覆盖了八成运维场景:
# 1. 找 7 天内改过的 .py,逐个做语法检查
find . -name "*.py" -mtime -7 -exec python -m py_compile {} \;
# 2. 找大于 100M 的文件,直接列出大小(不清空,先看)
find / -type f -size +100M -printf '%s\t%p\n' 2>/dev/null | sort -rn | head
# 3. 把找到的结果喂给 xargs 并行处理(快很多)
find . -name "*.log" -mtime +30 | xargs -P 4 -I{} gzip {}-printf 是 GNU find 的宝藏选项:能自定义每行输出格式(%s 字节数、%p 路径、%TY-%Tm-%Td 修改日期),比默认 -ls 好解析。配合 sort -rn 立刻得到"最大的文件排最前"。
八、性能与坑的边界情况
find /全盘扫很慢且满屏权限错:永远加2>/dev/null;生产上更该限定起点目录,比如find /var /home -name ...而不是find /。-mtime边界是"24 小时滚动窗口":find . -mtime 0指"修改时间在 24 小时内",不是"今天改的"。要按自然日,用-newermt "2026-08-29 00:00"更精确。-delete必须放最后:find . -delete -name "*.tmp"会先删光再判断名字,永远匹配不到;正确是find . -name "*.tmp" -delete。- 大量结果传给 xargs 默认单次上限:文件极多时 xargs 会自动分批,但若命令本身对参数个数敏感,用
-n 1强制一个一个来。
相关命令
一句话总结
find = 目录树里按条件找文件:-name(引号包通配) 按名、-type 按类型、-mtime -7 找 7 天内(+/-=之内/之前)、-size +100M 找大文件、-exec/管道 xargs 对结果批量执行;-path -prune 排除目录;记清 mtime(改内容)/atime(读)/ctime(改元数据) 三时间区别。