Linux: 文本搜索——grep 与正则表达式

在成千上万个文件中找到你要的那一行——这是 grep 的看家本领。它可能是 Linux 上用得最频繁的命令。

📋 前置知识:需要先掌握以下内容

1. 你将学到


2. 一个在百个文件中找代码的故事

(1) 痛点:想改一个接口名,不知道哪些文件用了它

小明需要将所有 Python 文件中调用 requests.get 的地方改为 httpx.get。项目有 100 多个文件,他不可能一个个打开看。

(2) grep 递归搜索

BASH
grep -rn "requests\.get" --include="*.py" src/

输出:

TEXT 📖 仅展示
src/api/client.py:15: response = requests.get(url, headers=headers)
src/api/users.py:42: data = requests.get(f"{API_URL}/users")
src/api/orders.py:78: result = requests.get(ORDER_URL)

3 个文件中有调用——不到 1 秒就找到了。

(3) 收益:从大海捞针到指哪打哪

小明养成了习惯:要改代码前先用 grep -rn 找到所有相关位置,确认后再动手。


3. 知识点讲解

(1) grep 基本用法

BASH
# 基本搜索
grep "pattern" filename

# 常用选项组合
grep -rn "TODO" src/    # 递归搜索,显示行号
grep -i "error" log.txt # 忽略大小写
grep -v "debug" log.txt # 反向匹配(不包含 debug 的行)
grep -c "failed" log.txt # 只计数
grep -l "main" *.py      # 只显示匹配的文件名
grep -A5 -B5 "exception" log.txt # 显示匹配行的前后各 5 行
选项 含义
-i 忽略大小写
-v 反向选择(显示不匹配的行)
-c 只输出匹配行数
-n 显示行号
-r-R 递归搜索子目录
-l 只显示包含匹配的文件名
-L 只显示不包含匹配的文件名
-w 匹配整个单词
-A NUM 显示匹配行后 NUM 行
-B NUM 显示匹配行前 NUM 行
-C NUM 显示匹配行前后各 NUM 行

(2) 基础正则表达式

元字符 含义 示例
. 匹配任意单个字符 h.t 匹配 hit / hot / hat
^ 行首 ^root 匹配以 root 开头的行
$ 行尾 bash$ 匹配以 bash 结尾的行
* 前一个字符重复 0 次或多次 ab*c 匹配 ac / abc / abbc
[abc] 匹配集合中任意一个 [Hh]ello 匹配 Hello 或 hello
[^abc] 匹配不在集合中的字符 [^0-9] 匹配非数字字符
\< 单词开头 \<root 匹配行首的 root
\> 单词结尾 root\> 匹配行尾的 root
💡 提示:正则中的 . 匹配任意单个字符——如果你需要匹配字面意义的点号(如 IP 地址中的 .),需要用反斜杠转义:grep "192\.168\." file 而非 grep "192.168." file(后者会匹配 192X168Y 等错误结果)。

(3) 扩展正则表达式(grep -E)

基础正则中 +?|{}() 需要转义才能用。扩展正则直接使用这些元字符(用 grep -Eegrep):

ℹ️ 说明:基础正则和扩展正则的主要区别在于,扩展正则(grep -E)中的 +?|{}() 不需要反斜杠转义即可使用。在基础正则中,grep "error\|warning" 需要转义 |,而 grep -E "error|warning" 直接写。建议优先使用 grep -E,语法更清晰。

元字符 含义 示例
+ 前一个字符重复 1 次或多次 ab+c 匹配 abc / abbc 但不匹配 ac
? 前一个字符出现 0 次或 1 次 colou?r 匹配 color 或 colour
` `
{n,m} 重复 n 到 m 次 [0-9]{3,5} 匹配 3-5 位数字
() 分组 `(error

▶ 示例:基本搜索

BASH
# 在文件中搜索
grep "root" /etc/passwd
# root:x:0:0:root:/root:/bin/bash

# 不区分大小写
echo -e "Error\nerror\nERROR" | grep -i "error"
# 三行全匹配

# 计数
grep -c "nologin" /etc/passwd
# 输出:16

# 显示行号
grep -n "www-data" /etc/passwd
# 33:www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

输出:

TEXT 📖 仅展示
root:x:0:0:root:/root:/bin/bash
Error
error
ERROR
16
33:www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

▶ 示例:反向匹配

BASH
# 排除注释行
grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"

# 排除 debug 日志
grep -v "DEBUG" app.log | grep "ERROR"

# 不包含特定扩展名的文件
ls -la | grep -v "\.md$"

输出:

TEXT 📖 仅展示
Port 22
PermitRootLogin no
PasswordAuthentication no
2026-07-07 10:23:45 ERROR Database connection failed
2026-07-07 10:24:12 ERROR Timeout waiting for response
drwxr-xr-x 2 alice alice 4096 Jul  7 10:00 src
-rw-r--r-- 1 alice alice 1234 Jul  7 10:00 config.yaml

▶ 示例:递归搜索代码

BASH
# 搜索项目中所有 TODO 注释
grep -rn "TODO\|FIXME\|HACK" --include="*.py" src/

# 在特定类型文件中搜索
grep -rn "def " --include="*.py" --include="*.js" .

# 排除 node_modules 搜索
grep -rn "api_key" --exclude-dir=node_modules --exclude-dir=.git .

# 只显示文件名
grep -rl "class User" src/

输出:

TEXT 📖 仅展示
src/api/client.py:23:# TODO: Add retry logic
src/models/user.py:45:# FIXME: Handle edge case
src/utils/helpers.py:12:# HACK: Temporary workaround
src/api/client.py:10:def get_user(user_id):
src/models/user.py:5:def validate_email(email):
config/settings.py:3:api_key = "sk-xxx"
src/models/user.py
src/auth.py
💡 提示grep -rn 是代码搜索的黄金组合——-r 递归搜索目录,-n 显示行号,配合 --include 限制文件类型。在大型项目中,grep -rn "pattern" --include="*.py" src/ 可以在一秒内定位目标代码。

▶ 示例:使用上下文

BASH
# 显示匹配行前后各 3 行
grep -C 3 "NullPointerException" app.log

# 显示匹配行后 5 行
grep -A 5 "Traceback" python_error.log

# 显示匹配行前 2 行
grep -B 2 "500" access.log

输出:

TEXT 📖 仅展示
10:23:01 INFO Processing request
10:23:02 WARN Memory usage high
10:23:03 ERROR NullPointerException at UserService.java:45
10:23:04 INFO Retrying operation
10:23:05 WARN Connection pool low
Traceback (most recent call last):
  File "app.py", line 42, in handle_request
    result = process(data)
  File "processor.py", line 15, in process
    return transform(input)
ValueError: Invalid input data
192.168.1.100 - - [07/Jul/2026:10:23:44] "POST /api/data"
192.168.1.100 - - [07/Jul/2026:10:23:45] "POST /api/data HTTP/1.1" 500 0

▶ 示例:正则表达式实战

BASH
# 匹配邮箱地址
grep -E "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" contacts.txt

# 匹配 IP 地址
grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log

# 匹配 URL
grep -E "https?://[^ ]+" index.html

# 匹配日期(YYYY-MM-DD)
grep -E "[0-9]{4}-[0-9]{2}-[0-9]{2}" logs/*.log

# 匹配以数字开头和字母结尾的行
grep "^[0-9].*[a-zA-Z]$" file.txt

输出:

TEXT 📖 仅展示
alice@example.com
bob.smith@company.org
contact@my-site.net
192.168.1.100 - - [07/Jul/2026] ...
10.0.0.45 - - [07/Jul/2026] ...
https://example.com/api/users
http://internal.server.local/status
2026-07-07
2026-07-08
1abc
23x

▶ 综合示例:日志错误分析

BASH
#!/bin/bash
# analyze-errors.sh - 日志错误分析

LOG_FILE="${1:-/var/log/syslog}"

echo "=== 错误分析报告 ==="
echo "源文件: $LOG_FILE"
echo ""

echo "1. 各类错误数量:"
grep -i "error" "$LOG_FILE" | awk '{print $5}' | sort | uniq -c | sort -rn | head -10

echo ""
echo "2. 最近 5 条错误:"
grep -i "error" "$LOG_FILE" | tail -5

echo ""
echo "3. 关键告警(OOM / Disk Full / Connection Refused):"
grep -iE "oom|out of memory|disk full|no space left|connection refused" "$LOG_FILE"

echo ""
echo "4. 错误趋势(按小时统计)":
grep -i "error" "$LOG_FILE" | grep -oP "\d{2}:\d{2}" | cut -d: -f1 | sort | uniq -c | sort -rn

❓ 常见问题

Q: grep 和正则有什么区别? A: grep 是一个命令行工具,用于在文件中搜索匹配模式的行;正则表达式(regex)是一种描述文本模式的语法。grep 支持正则表达式作为搜索模式,但正则本身只是语法规则,还可以用在 sed、awk、Python 等许多工具和语言中。

Q: grep -rgrep -R 一样吗? A: 基本一样。-R 会追踪符号链接,-r 默认不追踪。日常使用选哪个都可以。

Q: 怎么忽略大小写搜索? A:-i 选项:grep -ir "error" /var/log/

Q: 为什么 grep 有时找不到中文字符? A: 可能是 locale 问题。中文字符在 UTF-8 编码下是多字节的,grep 默认按字节匹配。试试 export LANG=zh_CN.UTF-8grep -P(Perl 正则模式)。

Q: grep -v 有什么用? A: 反向选择——输出不匹配模式的行。配合其他 grep 使用可以"排除"某些行,例如 grep -v "^#" 排除注释行,grep -v "^$" 排除空行。


📖 小节


📝 作业

  1. 基础题(难度⭐):在 /etc/passwd 中搜索使用 /bin/bash 作为登录 Shell 的用户,然后在 /var/log/syslog(或一个日志文件)中搜索错误并用 -c 统计数量
  2. 进阶题(难度⭐⭐):递归搜索一个项目目录,找出所有 FIXME 和 TODO 注释,然后用 grep -v 排除 .git 目录后统计项目代码行数
  3. 挑战题(难度⭐⭐⭐):用正则表达式匹配日志文件中的所有 IP 地址,并结合 sortuniq -c 统计每个 IP 的出现次数,找出访问最多的前 10 个 IP
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏