linux-grep命令


grep(Global Regular Expression Print)是Linux中一个强大的文本搜索工具,它可以在一个或多个文件中搜索匹配指定模式的行,并将匹配的行打印出来。grep支持基本正则表达式(BRE)和扩展正则表达式(ERE),是Linux系统中最常用的文本处理工具之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
➜ grep --help
用法: grep [选项]... PATTERN [FILE]...
在每个 FILE 或是标准输入中查找 PATTERN。
默认的 PATTERN 是一个基本正则表达式 (BRE)。
例如: grep -i 'hello world' menu.h main.c

正则表达式选择与解释:
-E, --extended-regexp PATTERN 是一个可扩展的正则表达式(ERE)
-F, --fixed-strings PATTERN 是一组由断行符分隔的固定字符串
-G, --basic-regexp PATTERN 是一个基本正则表达式(BRE)(默认)
-P, --perl-regexp PATTERN 是一个 Perl 正则表达式
-e, --regexp=PATTERN 用 PATTERN 来进行匹配操作
-f, --file=FILE 从 FILE 中取得 PATTERN
-i, --ignore-case 忽略大小写
-w, --word-regexp 强制 PATTERN 仅完全匹配字词
-x, --line-regexp 强制 PATTERN 仅完全匹配一行
-z, --null-data 一个 0 字节的数据行,但不是空行

杂项:
-s, --no-messages 抑制错误消息
-v, --invert-match 选中不匹配的行
-V, --version 显示版本信息并退出
--help 显示此帮助信息并退出

输出控制:
-m, --max-count=NUM NUM 次匹配后停止
-b, --byte-offset 输出的同时打印字节偏移
-n, --line-number 在输出的每一行前加上其所在文件中对应的行号
--line-buffered 每行输出后刷新输出缓冲区
-H, --with-filename 为每一匹配项打印文件名
-h, --no-filename 输出时不显示文件名前缀
--label=LABEL 将 LABEL 作为标准输入文件名前缀
-o, --only-matching 只显示匹配 PATTERN 的部分
-q, --quiet, --silent 不显示所有输出
--binary-files=TYPE 设定二进制文件的 TYPE 类型:
TYPE 可以是 'binary', 'text', 或 'without-match'
-a, --text 等同于 --binary-files=text
-I 等同于 --binary-files=without-match
-d, --directories=ACTION 读取目录的方式;
ACTION 可以是 'read', 'recurse', 或 'skip'
-D, --devices=ACTION 读取设备、先入先出队列、套接字的方式;
ACTION 可以是 'read''skip'
-r, --recursive 等同于 --directories=recurse
-R, --dereference-recursive
等同于 --directories=recurse --follow-symlinks
--include=FILE_PATTERN
只查找匹配 FILE_PATTERN 的文件
--exclude=FILE_PATTERN
跳过匹配 FILE_PATTERN 的文件和目录
--exclude-from=FILE 跳过所有匹配给定文件内容中任意模式的文件
--exclude-dir=PATTERN 跳过所有匹配 PATTERN 的目录
--include-dir=PATTERN 只查找匹配 PATTERN 的目录
-L, --files-without-match 只打印不匹配 FILE 的名称
-l, --files-with-matches 只打印匹配 FILE 的名称
-c, --count 只打印每个 FILE 中的匹配行数
-T, --initial-tab 使标签对齐(如果需要)
-Z, --null 在 FILE 名后输出一个 0 字节

上下文控制:
-B, --before-context=NUM 打印文本及其前面 NUM 行
-A, --after-context=NUM 打印文本及其后面 NUM 行
-C, --context=NUM 打印匹配行及其前后各 NUM 行
-NUM 等同于 -C NUM
--color[=WHEN],
--colour[=WHEN] 使用标记高亮匹配字串;
WHEN 可以是 'always', 'never''auto'
-U, --binary 不要清除行尾的 CR 字符(MSDOS/Windows)
--mmap 如果可能,忽略向后兼容性

当 FILE 是 '-' 时,读取标准输入。没有 FILE,读取 '.' 目录,除非指定了 -r 选项。
如果少于两个 FILE,假设使用 -h。如果有任意行被匹配,则退出状态为 0,
否则为 1;如果有错误产生,且未指定 -q,则退出状态为 2。

基本语法

grep的基本语法格式为:

1
grep [选项] PATTERN [FILE...]

其中:

  • PATTERN:要搜索的模式(可以是字符串或正则表达式)
  • FILE:要搜索的文件(可以是一个或多个文件,如果不指定则从标准输入读取)

常用选项

正则表达式选择

选项 说明
-E, --extended-regexp 使用扩展正则表达式(ERE)
-F, --fixed-strings 将PATTERN视为固定字符串,不使用正则表达式
-G, --basic-regexp 使用基本正则表达式(BRE),这是默认选项
-P, --perl-regexp 使用Perl正则表达式
-e, --regexp=PATTERN 指定匹配模式,可以多次使用来指定多个模式
-f, --file=FILE 从文件中读取模式,每行一个模式

匹配控制

选项 说明
-i, --ignore-case 忽略大小写
-v, --invert-match 反向匹配,显示不匹配的行
-w, --word-regexp 只匹配完整的单词
-x, --line-regexp 只匹配整行
-m, --max-count=NUM 最多匹配NUM行后停止

输出控制

选项 说明
-n, --line-number 显示匹配行的行号
-H, --with-filename 显示文件名(当搜索多个文件时默认启用)
-h, --no-filename 不显示文件名
-o, --only-matching 只显示匹配的部分,而不是整行
-c, --count 只显示匹配的行数,而不是匹配的行
-l, --files-with-matches 只显示包含匹配的文件名
-L, --files-without-match 只显示不包含匹配的文件名
-q, --quiet, --silent 静默模式,不输出任何内容,只返回退出状态码

上下文控制

选项 说明
-A, --after-context=NUM 显示匹配行及其后NUM行
-B, --before-context=NUM 显示匹配行及其前NUM行
-C, --context=NUM 显示匹配行及其前后各NUM行
-NUM 等同于 -C NUM

目录搜索

选项 说明
-r, --recursive 递归搜索目录
-R, --dereference-recursive 递归搜索目录,并跟随符号链接
--include=FILE_PATTERN 只搜索匹配FILE_PATTERN的文件
--exclude=FILE_PATTERN 跳过匹配FILE_PATTERN的文件
--exclude-dir=PATTERN 跳过匹配PATTERN的目录

基本使用示例

简单文本搜索

1
2
3
4
5
6
7
8
9
10
11
# 在文件中搜索包含"error"的行
➜ grep "error" log.txt

# 搜索多个文件
➜ grep "error" log1.txt log2.txt log3.txt

# 忽略大小写搜索
➜ grep -i "error" log.txt

# 显示行号
➜ grep -n "error" log.txt

反向匹配

1
2
3
4
5
# 显示不包含"error"的行
➜ grep -v "error" log.txt

# 显示不包含"error"和"warning"的行
➜ grep -v -e "error" -e "warning" log.txt

单词匹配

1
2
# 只匹配完整的单词"test",不会匹配"testing"或"contest"
➜ grep -w "test" file.txt

行匹配

1
2
# 只匹配整行都是"test"的行
➜ grep -x "test" file.txt

只显示匹配部分

1
2
3
# 只显示匹配的IP地址部分
echo "IP: 192.168.1.1" | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"
192.168.1.1

统计匹配行数

1
2
# 统计包含"error"的行数
➜ grep -c "error" log.txt

显示文件名

1
2
3
4
5
6
7
8
# 在多个文件中搜索,显示文件名
➜ grep -H "error" *.log

# 只显示包含匹配的文件名
➜ grep -l "error" *.log

# 只显示不包含匹配的文件名
➜ grep -L "error" *.log

正则表达式

grep支持基本正则表达式(BRE)和扩展正则表达式(ERE)。使用-E选项启用扩展正则表达式。

基本正则表达式(BRE)

符号 说明
. 匹配任意单个字符
* 匹配前一个字符0次或多次
^ 匹配行首
$ 匹配行尾
[] 匹配字符集中的任意一个字符
[^] 匹配不在字符集中的任意一个字符
\(\) 分组,保存匹配的内容
\{n\} 匹配前一个字符n次
\{n,\} 匹配前一个字符至少n次
\{n,m\} 匹配前一个字符n到m次

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 匹配以"test"开头的行
➜ grep "^test" file.txt

# 匹配以"test"结尾的行
➜ grep "test$" file.txt

# 匹配包含"test"或"Test"的行
➜ grep "[Tt]est" file.txt

# 匹配包含数字的行
➜ grep "[0-9]" file.txt

# 匹配包含3个连续数字的行
➜ grep "[0-9]\{3\}" file.txt

扩展正则表达式(ERE)

使用-E选项启用扩展正则表达式,语法更接近现代正则表达式:

符号 说明
+ 匹配前一个字符1次或多次
? 匹配前一个字符0次或1次
| 或运算符
() 分组(不需要转义)
{} 量词(不需要转义)

示例:

1
2
3
4
5
6
7
8
9
10
11
# 匹配"test"或"Test"
➜ grep -E "(T|t)est" file.txt

# 匹配一个或多个数字
➜ grep -E "[0-9]+" file.txt

# 匹配"color"或"colour"
➜ grep -E "colou?r" file.txt

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

上下文显示

显示匹配行的上下文

1
2
3
4
5
6
7
8
9
10
# 显示匹配行及其后3行
➜ grep -A 3 "error" log.txt

# 显示匹配行及其前3行
➜ grep -B 3 "error" log.txt

# 显示匹配行及其前后各3行
➜ grep -C 3 "error" log.txt
# 或者
➜ grep -3 "error" log.txt

示例输出:

1
2
3
4
5
6
➜ grep -C 2 "error" log.txt
line 10: some info
line 11: some info
line 12: error occurred
line 13: some info
line 14: some info

递归搜索

在目录中递归搜索

1
2
3
4
5
6
7
8
# 在当前目录及子目录中搜索
➜ grep -r "error" .

# 递归搜索并显示行号
➜ grep -rn "error" .

# 递归搜索并跟随符号链接
➜ grep -R "error" .

排除特定文件或目录

1
2
3
4
5
6
7
8
9
10
11
# 排除特定文件类型
➜ grep -r --exclude="*.log" "error" .

# 排除多个文件类型
➜ grep -r --exclude="*.log" --exclude="*.tmp" "error" .

# 排除特定目录
➜ grep -r --exclude-dir=".git" "error" .

# 只搜索特定文件类型
➜ grep -r --include="*.txt" "error" .

高级用法

多个模式匹配

1
2
3
4
5
# 使用-e选项指定多个模式(或关系)
➜ grep -e "error" -e "warning" log.txt

# 使用扩展正则表达式的或运算符
➜ grep -E "error|warning" log.txt

从文件读取模式

1
2
# 从文件patterns.txt中读取多个模式
➜ grep -f patterns.txt log.txt

patterns.txt内容示例:

1
2
3
error
warning
critical

限制匹配次数

1
2
# 每个文件最多显示5个匹配
➜ grep -m 5 "error" *.log

彩色输出

1
2
3
4
5
# 启用彩色输出(默认auto,在终端中自动启用)
➜ grep --color=always "error" log.txt

# 禁用彩色输出
➜ grep --color=never "error" log.txt

处理二进制文件

1
2
3
4
5
# 将二进制文件当作文本处理
➜ grep -a "pattern" binary_file

# 跳过二进制文件
➜ grep -I "pattern" *

管道组合

grep经常与其他命令组合使用:

1
2
3
4
5
6
7
8
9
10
11
# 查找进程
➜ ps aux | grep "nginx"

# 查找并统计
➜ ps aux | grep "nginx" | grep -v "grep" | wc -l

# 查找并排序
➜ grep "error" log.txt | sort | uniq

# 查找并提取
➜ ifconfig | grep -oE "inet [0-9.]+" | grep -oE "[0-9.]+"

实际应用场景

日志分析

1
2
3
4
5
6
7
8
9
10
11
# 查找错误日志
➜ grep -i "error" /var/log/app.log

# 查找特定时间段的日志
➜ grep "2024-01-27" /var/log/app.log | grep "error"

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

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

代码搜索

1
2
3
4
5
6
7
8
# 在代码中查找函数定义
➜ grep -r "function_name" src/

# 查找TODO注释
➜ grep -rn "TODO" src/

# 查找包含特定头文件的代码
➜ grep -r "#include.*stdio.h" src/

配置文件查找

1
2
3
4
5
# 查找配置文件中的配置项
➜ grep -E "^[^#]*key" config.conf

# 查找非注释行
➜ grep -v "^#" config.conf | grep -v "^$"

系统管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查找特定用户的所有进程
➜ ps aux | grep "^username"

# 查找监听特定端口的进程
➜ netstat -tuln | grep ":80 "

# 查找特定文件的所有引用
➜ grep -r "filename" /path/to/search

# 查找系统服务状态
➜ systemctl list-units | grep "running"

# 查找特定用户的登录记录
➜ last | grep "username"

# 查找磁盘使用情况
df -h | grep -E "/dev/sd|/dev/nvme"

# 查找内存使用情况
➜ free -h | grep "Mem"

# 查找网络接口
➜ ip addr show | grep -E "^[0-9]+:|inet "

数据分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 提取日志中的时间戳
➜ grep -oE "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}" log.txt

# 统计每小时错误数量
➜ grep "error" log.txt | grep -oE "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:" | sort | uniq -c

# 提取数值并计算总和
➜ grep -oE "[0-9]+\.[0-9]+" data.txt | awk '{sum+=$1} END {print sum}'

# 查找最频繁出现的IP地址
➜ grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" access.log | sort | uniq -c | sort -rn | head -10

# 提取JSON中的特定字段
➜ grep -oE '"key":\s*"[^"]*"' file.json

# 统计不同错误类型
➜ grep -oE "error|warning|critical" log.txt | sort | uniq -c

代码审查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查找硬编码的密码或密钥
➜ grep -riE "(password|secret|key|token)\s*=\s*['\"][^'\"]+['\"]" src/

# 查找TODO和FIXME注释
➜ grep -rnE "(TODO|FIXME|XXX|HACK)" src/

# 查找调试代码
➜ grep -rnE "(console\.log|print\(|debugger|var_dump)" src/

# 查找未使用的导入
➜ grep -r "import.*from" src/ | grep -v "//.*import"

# 查找长函数(超过50行)
➜ grep -n "function" src/ | awk -F: '{print $1}' | while read line; do
# 检查函数长度逻辑
done

# 查找魔法数字
➜ grep -rnE "\b[0-9]{3,}\b" src/ | grep -vE "(version|date|year|port)"

# 查找SQL注入风险
➜ grep -rnE "query.*\+.*['\"]" src/

安全审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查找可能的SQL注入点
➜ grep -rnE "(query|execute|exec).*\+" src/

# 查找eval使用
➜ grep -rn "eval(" src/

# 查找文件上传功能
➜ grep -rnE "(upload|file.*put|multipart)" src/

# 查找敏感信息泄露
➜ grep -riE "(api[_-]?key|apikey|secret[_-]?key|private[_-]?key)" src/

# 查找不安全的随机数生成
➜ grep -rnE "Math\.random|rand\(\)" src/

# 查找XSS风险
➜ grep -rnE "innerHTML|document\.write" src/

网络分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 从tcpdump输出中提取IP地址
➜ tcpdump -n | grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}"

# 分析访问日志中的用户代理
➜ grep -oE "Mozilla/[^)]+" access.log | sort | uniq -c | sort -rn

# 提取HTTP状态码
➜ grep -oE "HTTP/[0-9]\.[0-9]\s+[0-9]{3}" access.log | sort | uniq -c

# 查找慢请求(响应时间>1秒)
➜ grep -E "time:[0-9]{4,}" access.log

# 统计不同HTTP方法的请求数
➜ grep -oE "^(GET|POST|PUT|DELETE|PATCH)" access.log | sort | uniq -c

文件管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查找包含特定内容的文件
➜ grep -rl "pattern" /path/to/search

# 查找并列出文件大小
➜ grep -rl "pattern" . | xargs ls -lh

# 查找并备份匹配的文件
➜ grep -rl "pattern" . | xargs -I {} cp {} {}.bak

# 查找重复内容
➜ find . -type f -exec grep -l "exact_content" {} \; | sort

# 查找大文件中的特定内容
➜ grep "pattern" large_file.txt | head -100

# 查找并统计文件中的行数
➜ grep -l "pattern" *.txt | xargs wc -l

常见问题与技巧

排除grep自身

当使用ps等命令时,grep会匹配到自己:

1
2
3
4
5
6
7
8
9
10
11
# 错误的方式(会包含grep进程)
➜ ps aux | grep "nginx"

# 正确的方式(排除grep)
➜ ps aux | grep "nginx" | grep -v "grep"

# 或者使用正则表达式(推荐)
➜ ps aux | grep "[n]ginx"

# 使用pgrep(更专业的方式)
➜ pgrep -af nginx

处理特殊字符

当搜索包含特殊正则表达式字符的字符串时,需要使用-F选项或转义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 搜索包含点号的字符串
➜ grep -F "192.168.1.1" file.txt

# 或者转义
➜ grep "192\.168\.1\.1" file.txt

# 搜索包含括号的字符串
➜ grep -F "function()" file.txt

# 搜索包含方括号的字符串
➜ grep -F "[test]" file.txt

# 搜索包含美元符号的字符串
➜ grep -F "\$100" file.txt
# 或者
➜ grep -F '$100' file.txt

处理多行匹配

grep 默认是逐行匹配,要匹配跨行的内容需要使用特殊技巧:

1
2
3
4
5
6
7
8
# 使用-z选项处理以null分隔的行
➜ grep -z "pattern1.*pattern2" file.txt

# 使用tr将换行符替换为特殊字符
tr '\n' '|' < file.txt | grep "pattern1.*pattern2"

# 使用sed合并多行
➜ sed ':a;N;$!ba;s/\n/ /g' file.txt | grep "pattern"

字节偏移和行号

1
2
3
4
5
6
7
8
# 显示字节偏移
➜ grep -b "pattern" file.txt

# 同时显示行号和字节偏移
➜ grep -nb "pattern" file.txt

# 输出格式:文件名:行号:字节偏移:内容
➜ grep -Hnb "pattern" file.txt

处理大文件

1
2
3
4
5
6
7
8
9
10
11
# 使用--mmap选项(如果支持)
➜ grep --mmap "pattern" large_file.txt

# 限制输出行数
➜ grep "pattern" large_file.txt | head -1000

# 使用固定字符串模式(更快)
➜ grep -F "exact_string" large_file.txt

# 只显示文件名(不读取全部内容)
➜ grep -l "pattern" large_file.txt

调试正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用--color=always查看匹配部分
➜ grep --color=always "pattern" file.txt

# 使用-o选项只显示匹配部分
➜ grep -o "pattern" file.txt

# 测试正则表达式
echo "test string" | grep -E "pattern"

# 逐步构建复杂正则表达式
➜ grep -E "simple" file.txt
➜ grep -E "simple.*pattern" file.txt
➜ grep -E "(simple|complex).*pattern" file.txt

处理编码问题

1
2
3
4
5
6
7
8
# 指定文件编码
➜ LANG=C grep "pattern" file.txt

# 处理UTF-8编码
➜ LANG=en_US.UTF-8 grep "pattern" file.txt

# 忽略大小写(处理不同编码的大小写问题)
➜ grep -i "pattern" file.txt

性能优化技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 使用固定字符串(-F)而不是正则表达式
➜ grep -F "exact_string" file.txt # 快
➜ grep "exact_string" file.txt # 慢

# 2. 限制搜索范围
➜ grep -r --include="*.txt" "pattern" . # 只搜索.txt文件

# 3. 排除不需要的目录
➜ grep -r --exclude-dir=".git" --exclude-dir="node_modules" "pattern" .

# 4. 使用并行处理(配合find)
➜ find . -name "*.txt" -print0 | xargs -0 -P 4 grep "pattern"

# 5. 限制匹配次数
➜ grep -m 10 "pattern" file.txt # 找到10个匹配后停止

# 6. 只显示文件名(不读取全部内容)
➜ grep -l "pattern" *.txt

# 7. 使用静默模式进行条件判断
➜ grep -q "pattern" file.txt && echo "Found" || echo "Not found"

常见错误和解决方案

错误1:正则表达式不匹配

1
2
3
4
5
6
# 问题:想匹配点号但被解释为正则表达式
➜ grep "192.168.1.1" file.txt # 可能匹配 192x168x1x1

# 解决:使用-F选项或转义
➜ grep -F "192.168.1.1" file.txt
➜ grep "192\.168\.1\.1" file.txt

错误2:大小写敏感

1
2
3
4
5
# 问题:找不到匹配(大小写不匹配)
➜ grep "Error" file.txt # 找不到 "error"

# 解决:使用-i选项
➜ grep -i "error" file.txt

错误3:单词边界问题

1
2
3
4
5
# 问题:匹配到部分单词
➜ grep "test" file.txt # 可能匹配 "testing", "contest"

# 解决:使用-w选项
➜ grep -w "test" file.txt

错误4:递归搜索权限问题

1
2
3
4
5
# 问题:权限错误信息干扰输出
➜ grep -r "pattern" / 2>&1 | grep -v "Permission denied"

# 解决:重定向错误输出
➜ grep -r "pattern" / 2>/dev/null

错误5:二进制文件干扰

1
2
3
4
5
6
# 问题:二进制文件输出乱码
➜ grep "pattern" *

# 解决:跳过二进制文件
➜ grep -I "pattern" *
➜ grep --binary-files=without-match "pattern" *

性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用固定字符串搜索(比正则表达式快)
➜ grep -F "pattern" large_file.txt

# 限制搜索深度(注意:grep本身不支持--max-depth,需要配合find)
➜ find . -maxdepth 2 -type f -exec grep "pattern" {} +

# 只搜索文本文件
➜ grep -r --include="*.txt" "pattern" .

# 使用mmap提高大文件性能
➜ grep --mmap "pattern" large_file.txt

# 限制匹配次数,找到后立即停止
➜ grep -m 1 "pattern" large_file.txt

# 使用固定字符串模式(-F)比正则表达式快得多
➜ grep -F "exact_string" large_file.txt

grep 变体

egrep

egrepgrep -E 的简写形式,使用扩展正则表达式:

1
2
3
# 以下两个命令等价
➜ egrep "error|warning" log.txt
➜ grep -E "error|warning" log.txt

fgrep

fgrepgrep -F 的简写形式,将模式视为固定字符串:

1
2
3
# 以下两个命令等价
➜ fgrep "192.168.1.1" file.txt
➜ grep -F "192.168.1.1" file.txt

rgrep

rgrepgrep -r 的简写形式,递归搜索目录:

1
2
3
# 以下两个命令等价
➜ rgrep "pattern" .
➜ grep -r "pattern" .

注意:现代 Linux 系统中,这些变体通常只是 grep 的符号链接,建议直接使用 grep 配合相应选项。

Perl 正则表达式(-P选项)

使用 -P 选项可以启用 Perl 兼容的正则表达式,支持更强大的特性:

支持的 Perl 特性

特性 说明 示例
\d 匹配数字 \d+ 匹配一个或多个数字
\w 匹配单词字符 \w+ 匹配一个或多个单词字符
\s 匹配空白字符 \s+ 匹配一个或多个空白字符
\D 匹配非数字 \D+ 匹配一个或多个非数字
\W 匹配非单词字符 \W+ 匹配一个或多个非单词字符
\S 匹配非空白字符 \S+ 匹配一个或多个非空白字符
\b 单词边界 \bword\b 匹配完整的单词
\B 非单词边界 \Bword\B 匹配不在单词边界的部分
(?=...) 正向先行断言 \d+(?=px) 匹配后面跟着px的数字
(?!...) 负向先行断言 \d+(?!px) 匹配后面不跟着px的数字
(?<=...) 正向后行断言 (?<=\$)\d+ 匹配前面有$的数字
(?<!...) 负向后行断言 (?<!\$)\d+ 匹配前面没有$的数字
(?:...) 非捕获组 (?:error|warning) 分组但不捕获
\1, \2, ... 反向引用 (.)\1 匹配重复字符

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 匹配邮箱地址
➜ grep -P "[\w\.-]+@[\w\.-]+\.\w+" file.txt

# 匹配IP地址(更精确)
➜ grep -P "\b(?:\d{1,3}\.){3}\d{1,3}\b" file.txt

# 匹配重复单词
➜ grep -P "\b(\w+)\s+\1\b" file.txt

# 匹配十六进制颜色值
➜ grep -P "#[0-9A-Fa-f]{6}" file.txt

# 匹配URL
➜ grep -P "https?://[^\s]+" file.txt

# 使用正向先行断言匹配价格(不包含货币符号)
➜ grep -P "(?<=\$)\d+\.\d{2}" file.txt

注意-P 选项在某些系统上可能不可用,或者需要安装 pcregrep

复杂正则表达式示例

匹配常见模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 匹配日期格式 YYYY-MM-DD
➜ grep -E "([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])" file.txt

# 匹配时间格式 HH:MM:SS
➜ grep -E "([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]" file.txt

# 匹配手机号码(11位数字)
➜ grep -E "^1[3-9][0-9]{9}$" file.txt

# 匹配身份证号码(18位)
➜ grep -E "^[1-9][0-9]{5}(18|19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$" file.txt

# 匹配中文字符
➜ grep -P "[\u4e00-\u9fa5]+" file.txt

# 匹配HTML标签
➜ grep -E "<[^>]+>" file.txt

# 匹配注释行(#开头或//开头)
➜ grep -E "^\s*(#|//)" file.txt

提取和替换

1
2
3
4
5
6
7
8
9
10
11
# 提取所有IP地址
➜ grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" file.txt

# 提取所有邮箱地址
➜ grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" file.txt

# 提取所有URL
➜ grep -oE "https?://[^\s]+" file.txt

# 提取所有数字
➜ grep -oE "[0-9]+" file.txt

退出状态码

grep 的退出状态码可以用于脚本中的条件判断:

退出码 说明
0 找到匹配的行
1 没有找到匹配的行
2 发生错误(如文件不存在,且未使用 -s 选项)

在脚本中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

# 检查文件中是否存在特定模式
if grep -q "error" log.txt; then
echo "发现错误!"
exit 1
fi

# 检查命令是否成功
if ! grep -q "success" log.txt; then
echo "未找到成功标记"
fi

# 使用退出状态码
grep "pattern" file.txt
case $? in
0) echo "找到匹配" ;;
1) echo "未找到匹配" ;;
2) echo "发生错误" ;;
esac

环境变量

grep 的行为可以通过环境变量控制:

环境变量 说明
GREP_OPTIONS 已废弃,不建议使用
GREP_COLOR 设置匹配文本的颜色(已废弃,使用 GREP_COLORS
GREP_COLORS 设置匹配文本的颜色和样式
LC_ALL, LC_CTYPE, LANG 控制字符编码和区域设置

GREP_COLORS 配置

1
2
3
4
5
6
7
8
9
10
11
12
# 设置匹配文本为红色背景
export GREP_COLORS='ms=01;31:mc=01;31:sl=:cx=:fn=35:ln=32:bn=32:se=36'

# 各字段说明:
# ms - 匹配的字符串
# mc - 匹配的上下文
# sl - 选中的行
# cx = 上下文行
# fn = 文件名
# ln = 行号
# bn = 字节偏移
# se = 分隔符

与其他工具的组合

grep + awk

1
2
3
4
5
6
7
8
# 查找并提取特定列
➜ grep "error" log.txt | awk '{print $1, $3}'

# 查找并计算平均值
➜ grep "time:" log.txt | awk '{sum+=$2; count++} END {print sum/count}'

# 查找并统计
➜ grep "error" log.txt | awk '{count[$1]++} END {for(i in count) print i, count[i]}'

grep + sed

1
2
3
4
5
6
7
8
# 查找并替换
➜ grep "error" log.txt | sed 's/error/ERROR/g'

# 查找并删除匹配行
➜ grep -v "debug" log.txt | sed '/^$/d'

# 查找并添加前缀
➜ grep "error" log.txt | sed 's/^/[ERROR] /'

grep + xargs

1
2
3
4
5
6
7
8
# 查找文件并对每个文件执行命令
➜ grep -l "pattern" *.txt | xargs rm

# 查找并批量处理(处理包含空格的文件名)
➜ grep -l "pattern" *.txt | xargs -I {} mv {} {}.bak

# 查找并统计每个文件中的匹配数
➜ grep -l "pattern" *.txt | xargs -I {} sh -c 'echo -n "{}: "; grep -c "pattern" {}'

grep + find

1
2
3
4
5
6
7
8
# 查找文件并在其中搜索
➜ find . -name "*.log" -exec grep -H "error" {} \;

# 查找文件并统计匹配数
➜ find . -type f -name "*.txt" -exec grep -c "pattern" {} \;

# 查找文件并显示匹配行号
➜ find . -type f -name "*.py" -exec grep -n "import" {} \;

grep + sort + uniq

1
2
3
4
5
6
7
8
# 查找、排序并去重
➜ grep "error" *.log | sort | uniq

# 统计匹配次数并排序
➜ grep -o "pattern" file.txt | sort | uniq -c | sort -rn

# 查找并统计每个IP的出现次数
➜ grep -oE "([0-9]{1,3}\.){3}[0-9]{1,3}" log.txt | sort | uniq -c | sort -rn

grep + cut

1
2
3
4
5
# 查找并提取特定字段
➜ grep "error" log.txt | cut -d' ' -f1,3

# 查找并提取特定列
➜ grep "error" log.txt | cut -c1-20

grep + head/tail

1
2
3
4
5
6
7
8
# 查找并显示前10个匹配
➜ grep "error" log.txt | head -10

# 查找并显示最后10个匹配
➜ grep "error" log.txt | tail -10

# 查找并显示匹配及其后5行,然后取前20行
➜ grep -A 5 "error" log.txt | head -20

grep + wc

1
2
3
4
5
6
7
8
# 统计匹配行数
➜ grep "error" log.txt | wc -l

# 统计匹配的单词数
➜ grep -o "error" log.txt | wc -l

# 统计匹配的文件数
➜ grep -l "pattern" *.txt | wc -l

grep + tee

1
2
3
4
5
# 查找并同时输出到文件和屏幕
➜ grep "error" log.txt | tee errors.txt

# 查找并追加到文件
➜ grep "warning" log.txt | tee -a errors.txt

grep + while 循环

1
2
3
4
5
6
7
8
9
10
# 对每个匹配的文件执行操作
➜ grep -l "pattern" *.txt | while read file; do
echo "Processing $file"
# 执行操作
done

# 处理每个匹配的行
➜ grep "error" log.txt | while read line; do
echo "Found: $line"
done

实用脚本示例

日志分析脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# 分析错误日志并生成报告

LOG_FILE="/var/log/app.log"
REPORT_FILE="error_report.txt"

echo "=== 错误日志分析报告 ===" > $REPORT_FILE
echo "生成时间: $(date)" >> $REPORT_FILE
echo "" >> $REPORT_FILE

# 统计错误总数
ERROR_COUNT=$(grep -c "error" $LOG_FILE)
echo "错误总数: $ERROR_COUNT" >> $REPORT_FILE

# 统计不同类型的错误
echo "" >> $REPORT_FILE
echo "错误类型统计:" >> $REPORT_FILE
grep -i "error" $LOG_FILE | grep -oE "\[.*\]" | sort | uniq -c | sort -rn >> $REPORT_FILE

# 显示最近的错误
echo "" >> $REPORT_FILE
echo "最近的10个错误:" >> $REPORT_FILE
grep -i "error" $LOG_FILE | tail -10 >> $REPORT_FILE

cat $REPORT_FILE

代码审查脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# 检查代码中的潜在问题

SRC_DIR="src/"

echo "=== 代码审查报告 ==="

# 检查TODO注释
echo "TODO注释:"
grep -rn "TODO" $SRC_DIR | head -20

# 检查调试代码
echo ""
echo "调试代码:"
grep -rnE "(console\.log|debugger|print\(|var_dump)" $SRC_DIR

# 检查硬编码密码
echo ""
echo "可能的硬编码密码:"
grep -rnE "(password|secret|key|token)\s*=\s*['\"][^'\"]+['\"]" $SRC_DIR

# 检查SQL注入风险
echo ""
echo "SQL注入风险:"
grep -rnE "(query|execute|exec).*\+" $SRC_DIR

文件搜索脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
# 在多个目录中搜索文件内容

PATTERN="$1"
if [ -z "$PATTERN" ]; then
echo "用法: $0 <pattern>"
exit 1
fi

SEARCH_DIRS=("src/" "docs/" "config/")

for dir in "${SEARCH_DIRS[@]}"; do
if [ -d "$dir" ]; then
echo "=== 搜索目录: $dir ==="
grep -rn "$PATTERN" "$dir" --include="*.txt" --include="*.md" --include="*.conf"
fi
done

监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
# 监控日志文件中的错误

LOG_FILE="/var/log/app.log"
ALERT_EMAIL="admin@example.com"
ERROR_THRESHOLD=10

# 检查最近1分钟的错误数
ERROR_COUNT=$(tail -1000 $LOG_FILE | grep -c "error")

if [ $ERROR_COUNT -gt $ERROR_THRESHOLD ]; then
echo "警告: 检测到 $ERROR_COUNT 个错误(阈值: $ERROR_THRESHOLD)"
# 发送邮件通知
echo "检测到大量错误,请检查日志" | mail -s "错误警报" $ALERT_EMAIL

# 显示最近的错误
echo "最近的错误:"
grep "error" $LOG_FILE | tail -20
fi

最佳实践

1. 使用合适的选项

1
2
3
4
5
6
7
8
9
10
11
# ✅ 好:使用固定字符串搜索精确匹配
grep -F "exact.string" file.txt

# ❌ 差:使用正则表达式搜索固定字符串
grep "exact\.string" file.txt

# ✅ 好:忽略大小写搜索
grep -i "error" file.txt

# ✅ 好:只匹配完整单词
grep -w "test" file.txt

2. 处理文件名

1
2
3
4
5
6
7
# ✅ 好:处理包含空格的文件名
grep "pattern" *.txt | while IFS= read -r line; do
echo "$line"
done

# ✅ 好:使用find配合grep处理特殊字符
find . -name "*.txt" -exec grep "pattern" {} +

3. 性能考虑

1
2
3
4
5
6
7
8
9
10
11
# ✅ 好:限制搜索范围
grep -r --include="*.txt" "pattern" .

# ✅ 好:排除不需要的目录
grep -r --exclude-dir=".git" --exclude-dir="node_modules" "pattern" .

# ✅ 好:使用固定字符串模式
grep -F "pattern" large_file.txt

# ❌ 差:在大型目录中递归搜索所有文件
grep -r "pattern" /

4. 错误处理

1
2
3
4
5
6
7
8
9
10
# ✅ 好:检查退出状态码
if grep -q "pattern" file.txt; then
echo "找到匹配"
fi

# ✅ 好:处理文件不存在的情况
grep "pattern" file.txt 2>/dev/null || echo "文件不存在或无法读取"

# ✅ 好:使用静默模式进行条件判断
grep -q "pattern" file.txt && action_if_found || action_if_not_found

5. 输出格式

1
2
3
4
5
6
7
8
# ✅ 好:显示文件名和行号
grep -Hn "pattern" *.txt

# ✅ 好:使用颜色高亮(在脚本中)
grep --color=always "pattern" file.txt | less -R

# ✅ 好:格式化输出
grep "pattern" file.txt | awk '{printf "文件: %s, 行: %s\n", FILENAME, $0}'

6. 正则表达式

1
2
3
4
5
6
7
8
9
10
11
# ✅ 好:使用扩展正则表达式简化语法
grep -E "(error|warning)" file.txt

# ✅ 好:转义特殊字符
grep "192\.168\.1\.1" file.txt

# ✅ 好:使用字符类
grep "[0-9]" file.txt

# ❌ 差:过度复杂的正则表达式(考虑使用awk或sed)
grep -E "(([0-9]{1,3}\.){3}[0-9]{1,3})|([a-z]+@[a-z]+\.[a-z]+)" file.txt

7. 脚本中的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ✅ 好:使用变量存储模式
PATTERN="error"
grep "$PATTERN" file.txt

# ✅ 好:检查命令是否存在
if command -v grep >/dev/null 2>&1; then
grep "pattern" file.txt
else
echo "grep命令未找到"
fi

# ✅ 好:使用函数封装常用操作
search_in_files() {
local pattern="$1"
shift
grep -r "$pattern" "$@"
}

总结

grep 是 Linux 系统中最强大的文本搜索工具之一。掌握 grep 的关键点:

  1. 选择合适的模式:固定字符串(-F)vs 正则表达式
  2. 使用正确的选项:-i(忽略大小写)、-w(单词匹配)、-r(递归搜索)
  3. 性能优化:限制搜索范围、使用固定字符串、排除不需要的目录
  4. 错误处理:检查退出状态码、处理文件不存在的情况
  5. 组合使用:与其他工具(awk、sed、find等)组合使用
  6. 正则表达式:掌握基本和扩展正则表达式,了解 Perl 正则表达式

通过合理使用 grep,可以大大提高文本处理和系统管理的效率。

参考文献


文章作者: djaigo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 djaigo !
评论
  目录