find —— 按条件找文件并直接处理
find —— 按条件找文件并直接处理
分类:03 文件与传输 适用:全平台(GNU findutils;macOS 为 BSD find,参数有差异) 一句话:磁盘满了、权限乱了、要批量处理文件,
find是唯一不需要背复杂脚本的工具。
1. 它解决什么问题
- 找出 7 天前的日志并删除。
- 找出大于 1G 的文件,看谁占空间。
- 批量改权限、批量改名、批量 grep。
- 找属于已删除用户的文件、找 SUID 文件(安全审计)。
2. 基本结构
find <起点> <条件> <动作>
find /var/log -name '*.log' -mtime +7
find / -type f -size +1G 2>/dev/null
默认动作是 -print,所以不写动作就输出路径。
3. 常用条件
按名字/路径
find . -name '*.conf' # 区分大小写
find . -iname '*.CONF' # 忽略大小写
find . -path '*/nginx/*.conf' # 路径匹配(含通配)
find . -regex '.*\.\(jpg\|png\)$' # 正则(整路径匹配)
find . -not -name '*.log' # 排除
find . -name '*.log' ! -name 'access*'
按类型
find . -type f # 普通文件
find . -type d # 目录
find . -type l # 软链接
find . -type s # socket
find . -type p # 命名管道
按时间
find . -mtime -7 # 7 天内修改
find . -mtime +30 # 30 天前修改
find . -mmin -10 # 10 分钟内修改
find . -atime +90 # 90 天未访问
find . -ctime +180 # 180 天前元数据变更(权限/属主)
find . -newer /tmp/ref # 比参考文件新
find . -newermt '2026-01-01' # 指定时间之后
find . -newermt '2026-01-01' ! -newermt '2026-02-01'
-mtime n的 n 是"24 小时块"计数,-mtime -1表示不足 1 天,不是"今天"。要精确到分钟用-mmin。
按大小
find . -size +100M # 大于 100MB
find . -size -1k # 小于 1KB
find . -size +0 # 非空文件
find . -empty # 空文件/空目录
单位:c 字节、k KB、M、G。注意 -size 1M 表示"恰好 1M 的块",实际很少用,一般用 +/-。
按权限/属主
find . -perm 644 # 权限恰好 644
find . -perm -644 # 至少包含 644(rw-r--r--)
find . -perm /u+s # 任意 SUID
find . -perm -4000 # SUID(安全审计)
find . -perm -o+w # 任何人可写(风险)
find . -user nginx
find . -group www
find . -nouser -o -nogroup # 属主/属组已不存在
按数量/硬链接
find . -links +2 # 硬链接数 > 2
find . -inum 131074 # 按 inode(处理怪文件名)
find . -samefile /path/ref # 同 inode
4. 控制遍历
-maxdepth 1 # 只看当前层(不递归)
-mindepth 2 # 跳过第一层
-xdev # 不跨文件系统(备份/清理必用)
-prune # 剪枝,配合 -path 排除目录
只扫当前目录:
find /var/log -maxdepth 1 -type f -name '*.log'
排除某目录:
find /data -path /data/cache -prune -o -type f -name '*.tmp' -print
顺序要点:-prune 所在分支后面必须用 -o 接实际条件,并显式 -print。
5. 动作
打印与格式化
find . -name '*.log' -ls # 类似 ls -l
find . -type f -printf '%s\t%p\n' # 大小 + 路径
find . -printf '%TY-%Tm-%Td %TH:%TM %p\n' # 时间 + 路径
find /var/log -type f -printf '%s %p\n' | sort -nr | head # 最大的日志
-printf 常用占位:
| 占位 | 含义 |
|---|---|
%p |
路径 |
%f |
文件名 |
%s |
字节大小 |
%u / %g |
属主 / 属组 |
%m |
权限(八进制) |
%TY-%Tm-%Td |
修改日期 |
%TH:%TM |
修改时间 |
%i |
inode |
%h |
所在目录 |
执行命令
# 每个文件执行一次(慢,但兼容性好)
find . -name '*.tmp' -exec rm -f {} \;
# 批量传参(快,推荐)
find . -name '*.log' -exec gzip {} +
# 配合 sh -c 做复杂操作
find . -name '*.log' -exec sh -c 'echo "压缩 $1"; gzip "$1"' _ {} \;
# 批量改权限
find /var/www -type d -exec chmod 755 {} +
find /var/www -type f -exec chmod 644 {} +
find /var/www -type f -name '*.sh' -exec chmod 755 {} +
\; 与 + 的区别:
\;每个文件启动一次进程,10000 个文件 = 10000 次 fork。+把所有文件一次性传给命令,快几十倍,但参数过长时会自动分批。
删除
find /tmp -type f -name '*.tmp' -mtime +7 -delete
-delete 必须放在最后,且会自动开启 -depth(先处理子项)。
更稳的写法(先看再删):
find /tmp -type f -name '*.tmp' -mtime +7 -print # 先看清单
find /tmp -type f -name '*.tmp' -mtime +7 -delete # 确认后删
管道给 xargs
find . -type f -name '*.log' -print0 | xargs -0 gzip -9
find . -name '*.java' -print0 | xargs -0 grep -l 'TODO'
必须用 -print0 + xargs -0,否则文件名含空格/换行会断裂。
6. 实战场景
6.1 磁盘满了,找大文件
find / -xdev -type f -size +500M -printf '%s\t%p\n' 2>/dev/null \
| sort -nr | head -20 | awk '{printf "%.1fG\t%s\n", $1/1024/1024/1024, $2}'
-xdev 不跨挂载点,避免扫到 NFS/容器。
6.2 清理 30 天前日志(安全版)
# 1. 统计
find /var/log -type f -name '*.log' -mtime +30 | wc -l
# 2. 看总量
find /var/log -type f -name '*.log' -mtime +30 -printf '%s\n' | awk '{s+=$1} END {print s/1024/1024" MB"}'
# 3. 列出
find /var/log -type f -name '*.log' -mtime +30 -ls
# 4. 删除(先备份清单)
find /var/log -type f -name '*.log' -mtime +30 -print > /tmp/to_delete.txt
find /var/log -type f -name '*.log' -mtime +30 -delete
6.3 批量修权限(网站目录)
find /var/www/html -type d -exec chmod 755 {} +
find /var/www/html -type f -exec chmod 644 {} +
find /var/www/html -user root -exec chown www-data:www-data {} +
6.4 安全审计:找 SUID 与全局可写文件
find / -xdev -perm -4000 -type f -ls 2>/dev/null
find / -xdev -perm -o+w -type f -not -path '/proc/*' 2>/dev/null | head -50
find / -xdev \( -nouser -o -nogroup \) -ls 2>/dev/null
6.5 找出被删除但仍占空间的文件
find /proc/*/fd -lname '* (deleted)' -ls 2>/dev/null | head
# 更常用
lsof +L1
6.6 批量重命名(配合 shell)
find . -type f -name '*.JPG' -exec sh -c '
for f; do mv -- "$f" "${f%.JPG}.jpg"; done
' _ {} +
7. 常见坑
- 通配符要加引号:
-name *.log会被 shell 先展开,必须-name '*.log'。 2>/dev/null不可省:扫/时权限报错会刷屏并拖慢。-delete放错位置:放中间会把后续条件当动作,行为异常;永远放最后。-exec ... \;性能极差:大目录用+。-mtime不是"自然日":-mtime -1是 24 小时内,-mtime 0同理。- 不加
-xdev会跨挂载点:可能扫进 NFS、Ceph、/proc,卡死或误删。 -perm 644是精确匹配,找"至少 644"要用-perm -644。- 文件名含空格/换行:
-print0+xargs -0,否则rm会删错。 find遍历顺序不保证,依赖顺序的逻辑要显式sort。- macOS 的 BSD find 不支持
-printf、-delete部分用法,用gfind(brew install findutils)。 -newer比较的是 mtime,要比较 ctime 用-cnewer。-prune与-delete冲突:-delete隐含-depth,-prune失效,改写逻辑。
8. 速查表
find . -name '*.log' # 按名
find . -type f -size +100M # 大文件
find . -type f -mtime +30 # 30 天前
find . -type f -mmin -10 # 10 分钟内
find . -perm -4000 -type f # SUID
find . -empty # 空文件/目录
find . -maxdepth 1 -type f # 只看本层
find / -xdev -type f -size +1G 2>/dev/null # 全盘大文件
find . -name '*.tmp' -print # 先看
find . -name '*.tmp' -delete # 再删
find . -name '*.log' -exec gzip {} + # 批量处理
find . -print0 | xargs -0 rm -f # 安全管道
find . -type f -printf '%s\t%p\n' | sort -nr | head
find . -path ./cache -prune -o -type f -print