Linux教程 / 第 40 节

第4章:文件查找与搜索

掌握强大的文件查找和内容搜索工具

本章目标

  • 掌握find命令查找文件
  • 学会使用grep搜索文件内容
  • 了解locate快速定位文件
  • 掌握正则表达式基础
  • 能够快速定位配置文件和日志错误

4.1 按名称查找文件 (find)

4.1.1 find命令基础

find是Linux中最强大的文件查找工具。

基本语法

find [路径] [选项] [表达式]

基本用法

# 查找当前目录下的所有文件
find .

# 查找指定目录下的所有文件
find /home/jack

# 查找根目录下的所有文件 (慎用,会很慢)
find /

4.1.2 按文件名查找

# 按文件名查找 (-name,区分大小写)
find . -name "file.txt"

# 不区分大小写 (-iname)
find . -iname "file.txt"

# 使用通配符
find . -name "*.txt"           # 所有.txt文件
find . -name "test*"           # 以test开头的文件
find . -name "*config*"        # 包含config的文件

# 查找多种类型的文件
find . -name "*.txt" -o -name "*.md"
# -o 表示 OR (或)

# 排除某些文件
find . -name "*.txt" ! -name "test*"
# ! 表示 NOT (非)

4.1.3 按文件类型查找

# 按类型查找 (-type)
find . -type f    # 普通文件 (file)
find . -type d    # 目录 (directory)
find . -type l    # 符号链接 (symbolic link)
find . -type b    # 块设备
find . -type c    # 字符设备
find . -type s    # socket
find . -type p    # 管道

# 组合使用
find . -type f -name "*.txt"    # 查找所有.txt文件
find . -type d -name "test*"    # 查找以test开头的目录

4.1.4 按文件大小查找

# 按大小查找 (-size)
find . -size 100c      # 恰好100字节 (c=bytes)
find . -size 100k      # 恰好100KB (k=kilobytes)
find . -size 100M      # 恰好100MB (M=megabytes)
find . -size 1G        # 恰好1GB (G=gigabytes)

# 大于/小于
find . -size +100M     # 大于100MB
find . -size -1M       # 小于1MB

# 范围查找
find . -size +10M -size -100M    # 10MB到100MB之间

# 实用示例
find . -type f -size +100M       # 查找大于100MB的文件
find /var/log -size +1G          # 查找大于1GB的日志文件

4.1.5 按时间查找

# 按修改时间查找 (-mtime: modification time)
find . -mtime 0        # 最近24小时内修改
find . -mtime -7       # 最近7天内修改
find . -mtime +30      # 30天前修改

# 按访问时间查找 (-atime: access time)
find . -atime -7       # 最近7天内访问

# 按状态改变时间查找 (-ctime: change time)
find . -ctime -7       # 最近7天内状态改变

# 按分钟查找
find . -mmin -60       # 最近60分钟内修改
find . -mmin +120      # 120分钟前修改

# 实用示例
find . -type f -mtime -1           # 查找昨天修改的文件
find /var/log -mtime +7            # 查找7天前的日志
find . -name "*.log" -mtime +30    # 查找30天前的日志文件

4.1.6 按权限查找

# 按权限查找 (-perm)
find . -perm 644       # 恰好是644权限
find . -perm -644      # 至少包含644权限
find . -perm /644      # 包含任意一个权限位

# 查找可执行文件
find . -type f -perm -111    # 所有人都可执行
find . -type f -perm /111    # 任何人可执行

# 查找有SUID权限的文件
find / -perm -4000 2>/dev/null

# 实用示例
find . -type f -perm 777     # 查找777权限的文件(安全检查)

4.1.7 按所有者查找

# 按用户查找 (-user)
find . -user jack

# 按组查找 (-group)
find . -group developers

# 查找没有所有者的文件
find . -nouser

# 查找没有所属组的文件
find . -nogroup

# 实用示例
find /home -user jack -name "*.txt"

4.1.8 组合条件查找

# AND 条件 (默认)
find . -type f -name "*.txt" -size +1M
# 查找大于1MB的.txt文件

# OR 条件 (-o)
find . -name "*.txt" -o -name "*.md"
# 查找.txt或.md文件

# NOT 条件 (!)
find . -type f ! -name "*.txt"
# 查找非.txt文件

# 复杂组合
find . \( -name "*.txt" -o -name "*.md" \) -size +1M
# 查找大于1MB的.txt或.md文件

4.1.9 对查找结果执行操作

# 删除查找到的文件 (-delete)
find . -name "*.tmp" -delete

# 执行命令 (-exec)
find . -name "*.txt" -exec cat {} \;
# {} 代表找到的文件, \; 表示命令结束

# 批量重命名
find . -name "*.txt" -exec mv {} {}.bak \;

# 批量修改权限
find . -type f -exec chmod 644 {} \;
find . -type d -exec chmod 755 {} \;

# 显示详细信息
find . -name "*.log" -exec ls -lh {} \;

# 使用xargs (更高效)
find . -name "*.txt" | xargs cat
find . -name "*.log" | xargs grep "ERROR"

# 交互式确认 (-ok)
find . -name "*.tmp" -ok rm {} \;
# 每个文件都会询问是否执行

4.1.10 实用示例

# 查找并删除空文件
find . -type f -empty -delete

# 查找并删除空目录
find . -type d -empty -delete

# 查找重复文件 (按大小)
find . -type f -exec ls -l {} \; | sort -k5 -n

# 查找最大的10个文件
find . -type f -exec ls -lh {} \; | sort -k5 -hr | head -10

# 查找并压缩旧日志
find /var/log -name "*.log" -mtime +7 -exec gzip {} \;

# 查找并统计代码行数
find . -name "*.js" -exec wc -l {} \; | awk '{sum+=$1} END {print sum}'

# 查找最近修改的文件
find . -type f -mtime -1 -ls

# 查找包含特定内容的文件
find . -type f -name "*.txt" -exec grep -l "keyword" {} \;

4.2 搜索文件内容 (grep)

4.2.1 grep命令基础

grep = Global Regular Expression Print

基本语法

grep [选项] "搜索模式" [文件]

基本用法

# 在文件中搜索
grep "hello" file.txt

# 在多个文件中搜索
grep "hello" file1.txt file2.txt

# 从标准输入搜索
cat file.txt | grep "hello"
ps aux | grep "nginx"

4.2.2 常用选项

# 忽略大小写 (-i: ignore case)
grep -i "hello" file.txt

# 显示行号 (-n: line number)
grep -n "hello" file.txt

# 显示匹配的行数 (-c: count)
grep -c "hello" file.txt

# 只显示文件名 (-l: files with matches)
grep -l "hello" *.txt

# 显示不匹配的行 (-v: invert match)
grep -v "hello" file.txt

# 显示匹配的内容 (-o: only matching)
grep -o "hello" file.txt

# 递归搜索目录 (-r: recursive)
grep -r "hello" /path/to/dir

# 显示匹配行的前后几行
grep -A 3 "hello" file.txt    # 显示后3行 (After)
grep -B 3 "hello" file.txt    # 显示前3行 (Before)
grep -C 3 "hello" file.txt    # 显示前后3行 (Context)

# 使用扩展正则表达式 (-E)
grep -E "hello|world" file.txt

# 从文件读取搜索模式 (-f)
grep -f patterns.txt file.txt

# 显示不包含模式的文件 (-L)
grep -L "hello" *.txt

4.2.3 正则表达式基础

基本正则表达式

# 匹配任意字符 (.)
grep "h.llo" file.txt    # 匹配 hello, hallo, hxllo

# 匹配行首 (^)
grep "^hello" file.txt   # 匹配以hello开头的行

# 匹配行尾 ($)
grep "hello$" file.txt   # 匹配以hello结尾的行

# 匹配空行
grep "^$" file.txt

# 字符集 ([])
grep "[aeiou]" file.txt  # 匹配包含元音字母的行
grep "[0-9]" file.txt    # 匹配包含数字的行
grep "[a-z]" file.txt    # 匹配包含小写字母的行

# 否定字符集 ([^])
grep "[^0-9]" file.txt   # 匹配不包含数字的字符

# 重复 (*)
grep "hel*o" file.txt    # 匹配 heo, helo, hello, helllo

# 至少一次 (\+)
grep "hel\+o" file.txt   # 匹配 helo, hello, helllo

# 零次或一次 (\?)
grep "hel\?o" file.txt   # 匹配 heo, helo

# 精确重复 (\{n\})
grep "hel\{2\}o" file.txt    # 匹配 hello
grep "hel\{2,4\}o" file.txt  # 匹配 hello, helllo, hellllo

扩展正则表达式 (使用 -E 或 egrep)

# OR 操作 (|)
grep -E "hello|world" file.txt

# 分组 (())
grep -E "(hello|world) (foo|bar)" file.txt

# 重复 (+, ?, {})
grep -E "hel+o" file.txt     # 至少一个l
grep -E "hel?o" file.txt     # 零个或一个l
grep -E "hel{2,4}o" file.txt # 2到4个l

# 单词边界 (\b)
grep -E "\bhello\b" file.txt # 精确匹配单词hello

4.2.4 实用示例

# 查找IP地址
grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" file.txt

# 查找邮箱地址
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" file.txt

# 查找URL
grep -E "https?://[a-zA-Z0-9./?=_-]+" file.txt

# 查找日志中的错误
grep -i "error\|fail\|exception" /var/log/syslog

# 查找进程
ps aux | grep nginx

# 查找监听的端口
netstat -tuln | grep LISTEN

# 统计关键字出现次数
grep -o "hello" file.txt | wc -l

# 查找配置文件中的非注释行
grep -v "^#" /etc/nginx/nginx.conf | grep -v "^$"

# 高亮显示匹配内容 (--color)
grep --color "hello" file.txt

# 递归搜索项目中的TODO
grep -rn "TODO" src/

# 搜索多个关键字
grep -E "error|warning|critical" /var/log/app.log

4.3 快速定位文件 (locate)

4.3.1 locate命令

locate通过数据库快速查找文件,比find快得多。

# 安装locate (如果没有)
sudo apt install mlocate    # Ubuntu/Debian
sudo yum install mlocate    # CentOS/RHEL

# 更新数据库
sudo updatedb

# 查找文件
locate file.txt

# 忽略大小写
locate -i file.txt

# 只显示存在的文件
locate -e file.txt

# 限制结果数量
locate -n 10 file.txt

# 统计匹配数量
locate -c file.txt

# 使用正则表达式
locate -r "\.txt$"

locate vs find

特性locatefind
速度很快较慢
实时性依赖数据库更新实时
功能只能按名称查找功能强大
使用场景快速查找文件名复杂查找条件

4.3.2 which / whereis

# which - 查找命令的路径
which ls
# 输出: /usr/bin/ls

which python3
# 输出: /usr/bin/python3

# whereis - 查找命令、源码、手册
whereis ls
# 输出: ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz

whereis nginx
# 输出: nginx: /usr/sbin/nginx /etc/nginx /usr/share/man/man1/nginx.1.gz

4.4 实战场景:查找配置文件和日志错误

场景1: 查找配置文件

# 查找nginx配置文件
find /etc -name "nginx.conf" 2>/dev/null

# 或使用locate
locate nginx.conf

# 查找所有配置文件
find /etc -name "*.conf"

# 查找最近修改的配置文件
find /etc -name "*.conf" -mtime -7

# 查找包含特定配置的文件
grep -r "listen 80" /etc/nginx/

场景2: 查找日志中的错误

# 查找包含ERROR的日志行
grep "ERROR" /var/log/app.log

# 查找最近的错误 (显示后10行)
grep "ERROR" /var/log/app.log | tail -10

# 查找错误并显示上下文
grep -C 5 "ERROR" /var/log/app.log

# 查找多种错误类型
grep -E "ERROR|WARN|FATAL" /var/log/app.log

# 统计错误数量
grep -c "ERROR" /var/log/app.log

# 查找今天的错误
grep "$(date +%Y-%m-%d)" /var/log/app.log | grep "ERROR"

# 查找所有日志文件中的错误
find /var/log -name "*.log" -exec grep -l "ERROR" {} \;

# 实时监控错误日志
tail -f /var/log/app.log | grep --color "ERROR"

场景3: 查找大文件

# 查找大于100MB的文件
find / -type f -size +100M 2>/dev/null

# 查找并显示大小
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null

# 查找最大的10个文件
find / -type f -exec ls -lh {} \; 2>/dev/null | sort -k5 -hr | head -10

# 查找并删除临时大文件
find /tmp -type f -size +1G -mtime +7 -delete

场景4: 查找重复文件

# 按大小查找可能重复的文件
find . -type f -exec ls -l {} \; | awk '{print $5, $9}' | sort | uniq -d -w 10

# 使用fdupes工具 (需要安装)
sudo apt install fdupes
fdupes -r /path/to/dir

场景5: 清理旧文件

# 查找30天前的日志文件
find /var/log -name "*.log" -mtime +30

# 删除30天前的日志
find /var/log -name "*.log" -mtime +30 -delete

# 压缩7天前的日志
find /var/log -name "*.log" -mtime +7 -exec gzip {} \;

# 删除空文件和空目录
find . -type f -empty -delete
find . -type d -empty -delete

4.5 常用命令速查

命令说明示例
find查找文件find . -name "*.txt"
find -type按类型查找find . -type f
find -size按大小查找find . -size +100M
find -mtime按时间查找find . -mtime -7
find -exec执行命令find . -name "*.txt" -exec cat {} \;
grep搜索内容grep "hello" file.txt
grep -r递归搜索grep -r "hello" dir/
grep -i忽略大小写grep -i "hello" file.txt
grep -n显示行号grep -n "hello" file.txt
grep -v反向匹配grep -v "hello" file.txt
locate快速查找locate file.txt
which查找命令路径which ls

4.6 常见问题与解决

Q1: find命令太慢怎么办?

# 限制搜索深度
find . -maxdepth 3 -name "*.txt"

# 使用locate代替
locate file.txt

# 排除某些目录
find . -path ./node_modules -prune -o -name "*.txt" -print

Q2: 如何排除某些目录?

# 排除node_modules
find . -path ./node_modules -prune -o -name "*.js" -print

# 排除多个目录
find . \( -path ./node_modules -o -path ./.git \) -prune -o -name "*.js" -print

Q3: grep如何显示文件名?

# 默认多个文件会显示文件名
grep "hello" *.txt

# 单个文件强制显示文件名 (-H)
grep -H "hello" file.txt

# 不显示文件名 (-h)
grep -h "hello" *.txt

Q4: 如何搜索二进制文件?

# grep默认会跳过二进制文件
# 强制搜索 (-a)
grep -a "hello" binary-file

# 或使用strings
strings binary-file | grep "hello"

Q5: 如何提高grep性能?

# 使用固定字符串搜索 (-F)
grep -F "hello" large-file.txt

# 限制搜索的文件类型
grep "hello" --include="*.txt" -r .

# 排除某些文件
grep "hello" --exclude="*.log" -r .

4.7 本章小结

本章学习了文件查找与搜索:

find命令: 按名称、类型、大小、时间查找文件
grep命令: 搜索文件内容,支持正则表达式
locate命令: 快速定位文件
正则表达式: 掌握基本的正则表达式语法
实战应用: 查找配置文件、日志错误、大文件

关键要点

  • find功能强大但较慢,locate快速但依赖数据库
  • grep支持正则表达式,可以进行复杂的内容搜索
  • 善用管道组合命令,提高搜索效率
  • 使用-exec或xargs对查找结果批量操作

下一步学习

  • 第5章: 文件编辑与处理 - 学习vim、sed、awk

4.8 练习题

  1. 基础练习: 查找当前目录下所有.txt文件,并统计总数
  2. 进阶练习: 查找7天前修改的日志文件,并压缩它们
  3. 实战练习: 在项目中查找所有包含"TODO"的代码文件
  4. 挑战练习: 编写脚本,查找并删除重复文件

🎉 恭喜!你已经掌握了文件查找与搜索!

继续学习 → 第5章:文件编辑与处理