这个命令是干啥的
find 是 Linux 上最强大的文件搜索命令,没有之一。
跟 locate 这种靠数据库的搜索不同,find 是实时在磁盘上遍历目录树,你告诉它去哪找、找什么,它就一个个翻。虽然慢了那么一点,但结果绝对准确。而且它的过滤条件多到离谱:文件名、大小、时间、权限、类型、所属用户,你想到的它基本都能做。
我刚开始用 find 的时候觉得挺笨的,不就找个文件吗?后来有一次线上出了问题,需要在 200G 的日志目录里找 30 天前的 .tar.gz 文件来清理,find 一条命令搞定,换成手动翻目录得翻到猴年马月。从那以后我就服了。
基本用法(3分钟上手)
按名字找:-name 和 -iname
# 在当前目录下找叫 readme.txt 的文件
find . -name "readme.txt"
# 找所有 .log 结尾的文件
find /var/log -name "*.log"
# -iname 忽略大小写(找 readme、Readme、README 等)
find . -iname "readme*"
按类型找:-type
# 只找文件(不包含目录)
find . -type f
# 只找目录
find . -type d
# 找符号链接
find . -type l
按大小找:-size
# 超过 100MB 的文件
find / -size +100M
# 小于 10KB 的文件
find . -size -10k
# 正好等于 1MB 的文件
find . -size 1M
这里的 + 表示大于,- 表示小于,不加就是等于。
单位的坑:k 是小写的千字节,M 和 G 是大写。
进阶骚操作
按时间找:-mtime、-atime、-ctime
这个我用的最多,尤其是清理旧日志的时候。
# 找7天前修改过的文件
find /var/log -name "*.log" -mtime +7
# 找1天内修改过的文件
find . -mtime -1
# 找刚好7天前访问过的文件
find . -atime 7
时间三兄弟的区别:
- ·
-mtime:文件内容修改时间 - ·
-atime:文件最后访问时间 - ·
-ctime:文件元数据(权限、属主等)改变时间
还有一个实用技巧:-mmin、-amin、-cmin 是按分钟算的,适合更精细的搜索。
# 最后30分钟内修改过的文件
find . -mmin -30
按权限找:-perm
# 找权限为 777 的文件
find / -type f -perm 0777
# 找其他用户有写权限的文件(模式:任何人都有w权限)
find / -type f -perm /o=w
# 找设置了 SUID 的可执行文件(安全扫描常用)
find / -type f -perm /4000
多条件组合
# 找超过500MB且7天前的日志文件
find /var/log -name "*.log" -size +500M -mtime +7
# 找属于 www-data 用户的 .php 文件
find /var/www -type f -name "*.php" -user www-data
# 找空文件或空目录
find . -empty
-exec:找到后直接执行操作
这是 find 的杀手锏功能。找到文件后可以直接对它们做操作。
# 找到 .tmp 文件并删除
find /tmp -name "*.tmp" -type f -exec rm {} \;
解释一下语法:{} 是占位符,find 会用找到的每个文件替换它。\; 是结束符,表示每条命令独立执行(分号在 shell 中有特殊意义,所以要加反斜杠转义)。
如果改成 + 结尾,就是批量传参:
# 和 xargs 类似,批量传参效率更高
find /tmp -name "*.tmp" -type f -exec rm {} +
-delete:直接删除
# 直接删除找到的文件(不用-exec)
find /tmp -name "*.tmp" -type f -delete
注意:-delete 非常直接,没有二次确认。建议先不加 -delete 跑一遍,确认结果正确再加。
我就吃过这个亏。有次想删 /tmp 下的 .tmp 文件,手滑写成了 find . -name "*.conf" -delete,结果当前目录下所有 .conf 文件没了。还好有 git 能恢复,不然就哭了。
-print0 配合 xargs
# 处理文件名带空格的情况
find /data -name "*.txt" -type f -print0 | xargs -0 rm
避坑指南
坑1:路径一定要写对
# find 的第一个参数是搜索起点
find . -name "*.txt" # . 表示当前目录
find / -name "*.txt" # / 表示整个文件系统(会很慢)
新手最容易犯的错:以为不写路径就会搜全盘。不会的,不写就用当前目录。
坑2:通配符要加引号
# 正确的写法
find . -name "*.log"
# 错误的写法(如果不巧当前目录有 .log 文件,shell 会先展开通配符)
find . -name *.log
不加引号的话,如果当前目录有 a.log,shell 会把这个命令变成 find . -name a.log,其他 .log 文件就找不到了。
坑3:权限问题
# 如果用非 root 用户搜 / 目录,会有很多 Permission denied 的报错
find / -name "*.conf" 2>/dev/null # 把错误信息丢到黑洞
坑4:-delete 的陷阱
# -delete 隐含了 -depth,可能删除顺序和预期不一样
find . -name "*.log" -delete # 没问题
find . -name "*.log" -type d -delete # 目录是空的才会被删
而且 -delete 不能和 -prune 同时用,会报错。
坑5:find 和 exec 的参数顺序
# {} 和 \; 要写对,中间可能有空格
find . -name "*.txt" -exec cp {} /backup/ \;
习惯写法:-exec command {} \; 或 -exec command {} +,我把这个记成了固定搭配。
实战场景
场景1:清理 N 天前的旧日志
这是生产环境最常用的场景:
# 删除30天前的.log.gz文件
find /var/log/myapp -name "*.log.gz" -type f -mtime +30 -delete
# 更保守的做法:先查出来看看,确认再删
find /var/log/myapp -name "*.log.gz" -type f -mtime +30 -exec ls -lh {} \;
# (检查确认没问题后)
find /var/log/myapp -name "*.log.gz" -type f -mtime +30 -delete
场景2:找大文件做优化
# 找出根目录下所有超过 500MB 的文件
find / -type f -size +500M -exec ls -lh {} \; 2>/dev/null | sort -rh -k5
这条命令用来定位什么文件最大,然后决定是清理还是归档。我在很多服务器上用它找过日志文件和备份文件,经常能释放几十 G 空间。
场景3:安全扫描
# 找所有 SUID 文件(普通用户能提权的风险点)
find / -type f -perm /4000 -ls 2>/dev/null
# 找属于 root 但其他用户可写的文件
find / -type f -user root -perm /o=w -ls 2>/dev/null
场景4:按权限批量修复
# 找所有 PHP 文件并设为 644
find /var/www -type f -name "*.php" -exec chmod 644 {} \;
# 找所有目录设为 755
find /var/www -type d -exec chmod 755 {} \;
场景5:找大文件脚本
#!/bin/bash
# 找出指定目录下最大的10个文件
TARGET_DIR=${1:-.}
echo "在 $TARGET_DIR 中查找最大的10个文件..."
find "$TARGET_DIR" -type f -exec ls -lh {} \; 2>/dev/null | \
awk '{print $5, $NF}' | \
sort -rh | \
head -10
场景6:按时间归档备份
# 找出7天内修改过的配置文件做备份
find /etc -type f -mtime -7 -exec cp --parents {} /backup/ \;
今日作业
你的 CentOS 服务器的 /var/log 目录堆满了日志。请写一条 find 命令完成以下要求:
1. 在 /var/log 下查找
2. 文件名以 .log 结尾
3. 文件类型为普通文件
4. 超过 30 天没有被修改过(mtime > 30)
5. 文件大小大于 100MB
6. 执行删除操作
写出这一条命令。建议先不加 -delete 跑一遍验证结果。