find 是什么
find 是 GNU findutils 里的递归查找工具:从指定路径出发遍历整棵目录树,对每个文件依次求值表达式,命中后可以只打印,也可以直接执行删除、压缩、改权限等动作。它的定位是实时、精确、可组合——locate 依赖 updatedb 预建的索引,秒级返回但结果可能过期;find 每次都实际遍历文件系统,慢一些,看到的却是当下真实状态。近年的 fd 类工具默认体验更好(自动忽略隐藏文件与 gitignore 规则),但 find 在 POSIX 环境普遍预装、表达式能力完整,仍是写脚本与巡检任务时的默认选择。
基本信息
| 适用平台 | Linux 各发行版默认预装(GNU findutils);macOS/BSD 自带的 find 缺 -printf、-regextype 等 GNU 扩展 |
|---|---|
| 命令语法 | find [路径...] [表达式];省略路径时默认从当前目录 . 开始 |
| 常用测试 | -name/-iname 名称、-type f|d|l 类型、-size 大小、-mtime/-mmin 时间、-perm 权限、-user/-group 属主、-maxdepth/-mindepth 深度 |
| 常用动作 | -print 输出(默认)、-print0 空字符分隔、-delete 删除、-exec 执行命令、-ls 列出详情 |
| 权限要求 | 遍历目录需要 r 与 x 权限,缺 x 会刷出 Permission denied(常见于 /root、其他用户的家目录、未授权挂载点) |
典型使用场景
- 定期清理:按天数和大小叠加条件找过期日志再删除,比手写通配符安全,因为误命中的概率随条件增加而下降
- 磁盘排查:定位某个目录下的大文件,配合 du 与 df 找出真实占用者
- 权限审计:找出其他用户可写的文件(-perm -0002)或属主异常的遗留文件,属于安全基线检查的常规项
- 批量处理:对命中集合统一执行动作,例如打包、压缩、改属组、重命名
- 代码仓库清理:先用 -name .git -prune 剪掉版本库与依赖目录,再统计或删除,避免误伤
- 变更核对:用 -newer 参考文件或 -mtime 时间窗,列出某次发布之后被改动过的文件
常用示例
常用示例
find /var/log -type f -name '*.log' -mtime +7 -size +10M -print # 条件叠加:7 天以上且大于 10MiB
find . -maxdepth 2 -type d | head -30 # 只看两层目录结构
find /data -name '*.tmp' -delete # 直接删除(先用 -print 空跑确认)
find /src -type f -exec gzip {} + # 批量压缩:+ 只启动一次进程
find . -name .git -prune -o -type f -name '*.py' -print # 剪掉 .git 再找 .py
find /logs -path '*/archive/*' -prune -o -name '*.log' -print0 | xargs -0 du -sh # 文件名含空格也安全
find /srv -type f -perm -0002 -printf '%m %u %p\n' # 审计其他用户可写的文件
find /etc -type f -newermt '2026-10-01' -print # 指定日期之后改动过的配置(GNU 扩展)常见条件对照
| 条件 | 含义 | 注意 |
|---|---|---|
| -name '*.log' | 按文件名匹配,区分大小写;-iname 忽略大小写 | 通配符必须加引号,否则被 shell 先展开 |
| -type f | 只要普通文件(d 目录、l 符号链接、b/c 设备文件) | 符号链接默认不跟随,需要跟随用 -L |
| -size +10M | 大于 10MiB;-10M 表示小于 | GNU find 先把大小向上取整到单位再比较,-size 1M 实际覆盖 1 字节到 1MiB |
| -mtime +7 / -mmin -30 | 按修改时间筛选,单位分别是天与分钟 | 时间按 24 小时整数段向下取整,-mtime +7 实际要满 8 天;要精确用 -mmin |
| -perm -0002 | 权限位包含其他用户可写(等价 -perm -o+w) | 前置 - 表示包含,不加表示精确等于 |
| -maxdepth N | 限制递归层数 | GNU find 建议紧跟在路径之后写,写在表达式中间会告警 |
-exec ... \; 每个文件 fork 一次进程,几千个文件就是几千次启动开销;-exec ... + 把命中结果攒成一批交给一次进程调用(受命令行长度限制),速度差距可达几十倍。脚本里默认写 +,只有需要逐文件单独执行时才用 \;。
表达式默认隐式 AND 且短路求值,-o 表示或,括号要用 \\( \\) 转义以免被 shell 吃掉。剪枝必须放在会被命中的位置:-name .git -prune -o -print 表示目录命中就剪枝、其他命中才打印;写成 -name .git -prune -print 则 .git 目录自身也会被打印出来。
-printf、-newermt、-regextype 属于 GNU 扩展,跨平台脚本不要用。要保证可移植,输出统一走 -print0 配 xargs -0 或 -exec ... +,时间条件用 -mtime/-mmin。
删除类动作先空跑:把 -delete 或 -exec rm 换成 -print,确认命中集合符合预期再换成真实动作。在 / 这类根路径上执行带 -delete 的 find 是灾难级误操作。