Linux 中的 find 命令:按名称、大小和时间查找文件的示例
find 遍历目录树并按条件筛选文件:find /path -name '*.log' 按名称查找,-type f 只选普通文件,-size +100M 大于 100 MB,-mtime -7 表示一周内修改过的文件。条件可以组合,找到的文件可以通过 -exec、-delete 执行操作,或交给 xargs 处理。
find 遍历目录树,按名称、类型、大小、修改时间、所有者和权限查找文件。通用格式为 find [搜索位置] [条件] [操作]。下面是适用于日常任务的 find linux 示例:找到一个配置文件,清理旧日志,或者查看是什么占满了磁盘。
find 的语法
find /var/log -type f -name '*.log' -mtime +30 -print
逐部分解释:
/var/log— 起始位置。可以指定多个目录,也可以写.(当前目录)。GNU find 不指定路径时在当前目录中搜索。-type f -name '*.log' -mtime +30— 条件(在文档中称为测试)。默认情况下条件之间是逻辑“与”的关系。-print— 操作:输出路径。如果没有其他操作,它会自动生效。
find 会递归进入所有子目录。如果以普通用户身份搜索系统路径,输出中会充斥着 Permission denied 行。可以把错误流重定向来去掉这些信息:
find / -name 'nginx.conf' 2>/dev/null
按名称查找:-name 和 -iname
条件 -name 只用模式比较文件名(不含路径)。模式支持 *(任意字符)、?(单个字符)和 [abc](列出的某个字符)。
# 精确的文件名
find /etc -name 'hosts'
# 所有 .conf 文件
find /etc -name '*.conf'
# 忽略大小写:README.md、readme.MD、Readme.md
find ~/projects -iname 'readme.md'
# report_1.csv ... report_9.csv
find . -name 'report_?.csv'
模式一定要加引号。否则 shell 会先根据当前目录中的文件展开 *.conf,find 收到的就是文件名列表而不是模式,结果会出乎意料,或者命令报错 paths must precede expression。
按路径查找:-path 和 -regex
如果目录比文件名更重要,使用 -path,它用模式匹配完整路径:
# 只在 src 目录下的 .js 文件
find . -path '*/src/*' -name '*.js'
对于更复杂的模式,可以使用 -regex(同样匹配完整路径),或使用不区分大小写的 -iregex:
find . -regextype posix-extended -regex '.*\.(jpg|jpeg|png)$'
如何排除目录
如果不希望 find 进入 node_modules 或 .git 等目录,可以使用 -prune:
find . -path ./node_modules -prune -o -name '*.js' -print
含义是:“如果路径是 ./node_modules,就不进入它,否则(-o)输出 *.js 文件”。末尾的显式 -print 是必需的,否则被排除的目录本身也会出现在输出中。更简单但较慢的写法是 -not -path '*/node_modules/*':find 仍会遍历该目录,只是过滤掉结果。
按类型查找:-type
| 取值 | 查找的对象 |
|---|---|
-type f | 普通文件 |
-type d | 目录 |
-type l | 符号链接 |
-type s | 套接字 |
-type p | 命名管道(FIFO) |
# 名为 logs 的目录
find / -type d -name 'logs' 2>/dev/null
# 空文件和空目录
find . -type f -empty
find . -type d -empty
# 失效的符号链接
find . -xtype l
按大小查找:-size
条件 -size 接受带后缀的数字:c 表示字节,k 表示千字节,M 表示兆字节,G 表示吉字节。加号 + 表示“大于”,减号 - 表示“小于”,没有符号表示“恰好等于”。
# 整个系统中大于 100 MB 的文件
find / -type f -size +100M 2>/dev/null
# 10 到 50 MB 之间
find . -type f -size +10M -size -50M
# 小于 1 KB
find . -type f -size -1k
需要注意:大小会向上取整到所用单位。因此 -size -1M 只会找到空文件,因为任何非空文件取整之后至少为 1 兆字节。如需精确的边界,请使用更小的单位:-size -1024k。
什么占用了磁盘空间
结合 find、ls 和 sort 可以列出最大的文件:
find /var -type f -size +50M -exec ls -lh {} + 2>/dev/null | sort -k5 -rh | head
-rw-r----- 1 syslog adm 1.2G Oct 14 09:12 /var/log/syslog.1
-rw-r--r-- 1 root root 412M Oct 10 03:00 /var/backups/db.sql.gz
-rw-r----- 1 root adm 96M Oct 14 09:15 /var/log/nginx/access.log
要评估整个目录的大小,du -sh 更合适;而 find 适合用来找出深处某个占满空间的大文件。
按时间查找:-mtime、-mmin、-newer
每个文件有三个时间戳,find 可以按任意一个进行筛选:
| 条件 | 时间戳 | 单位 |
|---|---|---|
-mtime / -mmin | 内容修改时间 | 天 / 分钟 |
-atime / -amin | 最后读取时间 | 天 / 分钟 |
-ctime / -cmin | 元数据修改时间(权限、所有者、名称) | 天 / 分钟 |
符号的含义与大小条件相同:-mtime -7 表示 7 天内修改过,-mtime +30 表示 30 天以前修改过。
# 最近一周修改过的文件
find ~/projects -type f -mtime -7
# 超过 30 天的日志
find /var/log -type f -name '*.log' -mtime +30
# 最近 15 分钟内修改过的文件
find /etc -type f -mmin -15
天数按完整的 24 小时周期计算,小数部分会被舍去。因此 -mtime +1 找到的是超过 48 小时的文件,而不是 24 小时——这是常见的陷阱。如果需要精确的时间,请改用分钟:-mmin +1440。
比某个文件或某个日期更新的文件
# 修改时间晚于 deploy.lock 的文件
find . -type f -newer deploy.lock
# 指定日期之后修改过的文件(GNU find)
find . -type f -newermt '2026-10-01'
# 指定日期区间内
find . -type f -newermt '2026-10-01' ! -newermt '2026-10-08'
按所有者和权限查找
# 属于用户 alice 的文件
find /home -user alice
# 所有者已不存在的文件(删除用户之后)
find / -nouser 2>/dev/null
# 权限恰好为 777 的文件
find /var/www -type f -perm 777
# 所有人都可写的文件
find /var/www -perm -o=w
# 设置了 SUID 位的文件——安全审计时很有用
find / -perm -4000 -type f 2>/dev/null
-perm 有三种形式:不带符号表示权限完全相同;带 - 表示至少设置了所列的所有位;带 / 表示至少设置了其中一个位。
条件的逻辑:与、或、非
条件默认以“与”连接。“或”使用 -o,取反使用 ! 或 -not。分组使用括号,括号需要转义,以免被 shell 解释:
# jpg 或 png 图片
find . -type f \( -name '*.jpg' -o -name '*.png' \)
# 除 .tmp 文件以外的所有内容
find . -type f ! -name '*.tmp'
如果没有括号,-type f 只会作用于“或”组合中的第一个条件,结果中就会出现名为 *.png 的目录。\( 和 \) 两侧的空格是必需的。
搜索深度:-maxdepth 和 -mindepth
# 只在当前目录,不进入子目录
find . -maxdepth 1 -type f -name '*.sh'
# 从第二层子目录开始
find . -mindepth 2 -name '*.md'
# 不跨越文件系统边界
find / -xdev -type f -size +1G
请把 -maxdepth 紧跟在路径之后,放在其他条件之前,否则 GNU find 会给出警告。在 / 上搜索时,选项 -xdev 很有用:find 不会进入 /proc、网络磁盘和挂载的磁盘。
对结果执行操作:-exec、-delete、xargs
-exec:对每个文件执行命令
find 会用文件路径替换 {}。命令以 \; 或 + 结束:
# 每个文件单独执行一次
find . -name '*.sh' -exec chmod +x {} \;
# 所有文件作为一个列表传入——更快
find . -name '*.log' -exec gzip {} +
# 对每个文件逐一确认
find . -name '*.bak' -ok rm {} \;
使用 + 时,路径会被分批传给命令,命令启动次数少得多,因此处理数千个文件时快很多。使用 \; 适用于只接受一个文件的命令,或者 {} 不在末尾的情况。
-delete:删除找到的文件
# 先查看会被删除的文件
find /tmp/build -type f -name '*.o' -mtime +7
# 然后再删除
find /tmp/build -type f -name '*.o' -mtime +7 -delete
始终先不带 -delete 运行命令并检查列表。并且把 -delete 放在最后:find 从左到右求值,find . -delete -name '*.o' 会先删除目录中的所有内容,然后才检查名称。
find 与 xargs
经典的组合是通过 xargs 把文件列表交给另一个程序。为了避免文件名中的空格导致出错,使用空字节作为分隔符:
find . -type f -name '*.txt' -print0 | xargs -0 wc -l
xargs 的 -P 参数可以并行处理:
find ./images -name '*.png' -print0 | xargs -0 -P 4 -n 10 optipng
find 与 grep:在文件内容中查找文本
find 查找的是文件,而不是文件内容。要在选中的文件中查找某个字符串,把文件交给 grep:
# 哪些配置文件中包含 listen 8080
find /etc/nginx -type f -name '*.conf' -exec grep -Hn 'listen 8080' {} +
/etc/nginx/sites-enabled/app.conf:4: listen 8080;
-H 输出文件名,-n 输出行号;grep -l 只输出包含匹配内容的文件名。如果只需要按扩展名过滤,直接使用 grep 就够了:grep -rn --include='*.conf' 'listen 8080' /etc/nginx。
自定义输出格式:-printf
GNU find 不仅能输出路径,还能输出大小、日期和名称:
find . -maxdepth 1 -type f -printf '%s\t%TY-%Tm-%Td\t%p\n' | sort -n
其中 %s 是字节大小,%T... 是修改日期的各个部分,%p 是路径。这对脚本很方便:不需要解析 ls 的输出。
速查表:日常的 find linux 示例
| 任务 | 命令 |
|---|---|
| 按名称查找文件 | find / -name 'file.txt' 2>/dev/null |
| 忽略大小写 | find . -iname '*.jpg' |
| 只查找目录 | find . -type d -name 'cache' |
| 大于 1 GB 的文件 | find / -xdev -type f -size +1G |
| 一天内修改过的文件 | find . -type f -mtime -1 |
| 一小时内修改过的文件 | find . -type f -mmin -60 |
| 删除 30 天前的日志 | find /var/log/app -name '*.log' -mtime +30 -delete |
| 空目录 | find . -type d -empty |
| 修改所有目录的权限 | find . -type d -exec chmod 755 {} + |
| 文件中包含某个字符串 | find . -name '*.py' -exec grep -l 'TODO' {} + |
| 统计文件数量 | find . -type f | wc -l |
常见错误
- 模式没有加引号。
find . -name *.log在当前目录中只要有一个.log文件就会出错。请写成'*.log'。 - 满屏的 Permission denied。 加上
2>/dev/null,或者在确实需要搜索整个磁盘时使用sudo。 -delete位置不对。 它应当始终放在最后,并且之前要先做一次不删除的检查运行。- 管道中的文件名含空格。
find ... | xargs rm会把 “My File.txt” 拆成两个参数。请使用-print0配合xargs -0,或使用-exec。 - 期望
-mtime给出精确的天数。 需要精确的时间区间时,请使用-mmin或-newermt。
总结
find 是通用的文件系统搜索工具:指定路径,设置按名称、类型、大小、时间和权限的条件,然后执行操作。掌握五个要点——-name、-type、-size、-mtime 和 -exec ... +——大多数任务一行命令就能完成。建议在自己的终端中把上面的 find linux 示例都试一遍;关于 find 与 grep、sed、awk 的配合,我们在 Linux 课程中关于终端文本处理的课时里有实际演示。
常见问题
find 与 locate 有什么区别?
locate 在预先建好的文件名数据库中查找,因此速度极快,但看不到上次更新数据库(命令 updatedb)之后创建的文件。find 实时遍历磁盘,并且可以按大小、时间和权限过滤。
如何按内容而不是文件名查找文件?
find 本身不读取文件内容。可以使用 grep -rn '文本' /路径,或者组合使用 find . -name '*.conf' -exec grep -l '文本' {} +。
为什么在根目录上运行 find 很慢?
它会遍历所有目录,包括 /proc、/sys 和挂载的磁盘。请把搜索范围限制在具体目录,加上 -xdev 和 -maxdepth,或者用 -prune 排除不需要的部分。
能否按修改日期对 find 的结果排序?
可以:find . -type f -printf '%T@ %p\n' | sort -n 会按从旧到新的顺序列出文件,其中 %T@ 是以秒计的自纪元以来的修改时间。
如何查找并删除空目录?
命令 find . -type d -empty -delete 会删除所有空目录,包括那些因为删除了子文件而变空的目录。请先不加 -delete 运行,检查列表之后再删除。