grep 命令用法解析
一、概述
grep(Global Regular Expression Print)是Linux/Unix系统中用于文本搜索的强大工具,可根据指定模式(正则表达式或普通字符串)在文件中查找匹配的行,并输出结果。其核心功能是模式匹配与过滤,支持基础正则(BRE)和扩展正则(ERE),广泛用于日志分析、代码检索、文本处理等场景。
二、基础用法
1. 基本语法
grep [选项] 模式 [文件...]
- 若不指定文件,默认从标准输入(管道输入)读取内容。
- 模式可分为普通字符串(精确匹配)和正则表达式(模式匹配)。
2. 常用基础选项
| 选项 | 作用 | 示例 |
|---|---|---|
| 无选项 | 查找包含指定字符串的行 | grep "error" log.txt(查找log.txt中含"error"的行) |
-n |
显示匹配行的行号 | grep -n "warn" app.log(输出含"warn"的行及行号) |
-H |
显示匹配行所在的文件名(多文件时默认开启) | grep -H "config" *.ini(显示含"config"的ini文件名及内容) |
-h |
抑制文件名输出(多文件时仅显示匹配内容) | grep -h "test" *.txt(仅输出匹配内容,不显示文件名) |
-C n |
显示匹配行及上下n行(Context) | grep -C2 "Exception" debug.log(显示异常行及上下2行) |
-A n |
显示匹配行及之后n行(After) | grep -A3 "start" service.log(显示启动行及后续3行) |
-B n |
显示匹配行及之前n行(Before) | grep -B1 "end" task.log(显示结束行及前1行) |
-o |
仅输出匹配的部分(而非整行) | grep -o "[0-9]\+" data.txt(仅提取文件中的数字) |
-r |
递归查找目录下所有文件 | grep -r "import" ./src(递归查找src目录中含"import"的行) |
3. 基础匹配示例
# 查找单个文件中包含"success"的行
grep "success" result.txt
# 查找多个文件中包含"failed"的行
grep "failed" test1.log test2.log
# 从标准输入中过滤(结合管道)
cat access.log | grep "404" # 查找访问日志中的404错误
三、高级用法
1. 模式匹配增强选项
| 选项 | 作用 | 示例 |
|---|---|---|
-i |
忽略大小写匹配 | grep -i "Case" code.py(匹配"Case"、“CASE”、"case"等) |
-w |
仅匹配完整单词(避免子串匹配) | grep -w "cat" text.txt(匹配"cat"但不匹配"category") |
-x |
仅匹配整行完全一致的内容 | grep -x "hello world" msg.txt(仅当行内容为"hello world"时匹配) |
-v |
反向匹配(输出不满足模式的行) | grep -v "^#" config.ini(输出非注释行,排除以#开头的行) |
-c |
统计匹配的行数 | grep -c "ERROR" system.log(统计日志中含"ERROR"的行数) |
-l |
仅显示包含匹配内容的文件名 | grep -l "database" ./conf/*(列出conf目录中含"database"的文件) |
-L |
仅显示不包含匹配内容的文件名 | grep -L "timeout" ./scripts/*(列出scripts目录中不含"timeout"的文件) |
2. 正则表达式深度应用
grep支持两种正则模式:基础正则(BRE) 和扩展正则(ERE),核心区别在于ERE无需对特殊符号转义(需通过-E启用)。
(1)基础正则(BRE)
需对+、?、|、()等符号转义(加\):
# 匹配连续1次及以上的数字(+需转义)
grep "num=[0-9]\+" form.txt # 匹配"num=123"、"num=45"等
# 匹配以"start"或"begin"开头的行(|需转义)
grep "^start\|^begin" task.txt # 匹配"start..."或"begin..."
# 匹配3-5位的数字({}需转义)
grep "id=[0-9]\{3,5\}" user.txt # 匹配"id=123"、"id=45678"等
(2)扩展正则(ERE,-E选项)
无需转义特殊符号,支持更复杂的模式:
# 匹配邮箱格式(简化版)
grep -E "[a-zA-Z0-9_]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}" emails.txt
# 匹配IP地址(严格版:0-255.0-255.0-255.0-255)
grep -E "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" ips.txt
# 匹配中国手机号(1开头,11位)
grep -E "1[3-9][0-9]{9}" phone_list.txt
3. 目录查找精细化控制
| 选项 | 作用 | 示例 |
|---|---|---|
--include=PATTERN |
仅查找匹配PATTERN的文件 | grep -r --include="*.py" "def" ./(递归查找所有py文件中的函数定义) |
--exclude=PATTERN |
排除匹配PATTERN的文件 | grep -r --exclude="*.log" "error" ./(递归查找时排除log文件) |
--exclude-dir=DIR |
排除指定目录 | grep -r --exclude-dir=".git" "config" ./(递归查找时排除.git目录) |
-maxdepth n |
限制递归深度(n为层数) | grep -r -maxdepth 2 "test" ./(仅查找当前目录及子目录,不深入更深层) |
四、扩展用法(组合与实战)
1. 多条件组合过滤
# 查找含"error"或"warn"的非注释行(忽略大小写)
grep -Ei -v "^#" "error|warn" app.log
# 查找含"TODO"但不含"FIXED"的Java文件
grep -r --include="*.java" -E "TODO" ./ | grep -v "FIXED"
2. 与其他命令协同
# 统计代码中有效注释行(排除空注释和纯#行)
grep -E "^#.*[^[:space:]]" code.py | wc -l
# 查找占用端口8080的进程(结合netstat)
netstat -tlnp | grep -oP ":8080\s.*?(\d+)/" | awk '{print $2}' # 提取进程ID
3. 性能优化技巧
- 优先指定文件类型(
--include)减少扫描范围; - 对大文件使用
-F(快速匹配,将模式视为普通字符串而非正则); - 结合
-m n限制最大匹配行数(找到n行后停止):grep -m 5 "error" large.log。
五、常见错误与注意事项
- 正则中特殊字符未转义:如
.在正则中表示任意字符,匹配实际.需转义为\.(例:grep "192\.168" ips.txt)。 -n与-o混用:-o仅输出匹配部分,-n的行号可能无意义,需根据需求选择。- 递归查找目录时遗漏
-r:未加-r会将目录视为文件,导致"Is a directory"错误。 - 扩展正则未加
-E:使用|、{}等符号时,需加-E否则会被视为普通字符。
通过上述用法,grep可高效完成文本过滤、模式匹配、批量检索等任务,是Linux系统中不可或缺的文本处理工具。
六、扩展:egrep
1. 定义与核心作用
egrep(Extended Global Regular Expression Print)是 grep 命令的扩展版本,专门用于支持扩展正则表达式(ERE),无需对 |、()、{}、+、? 等扩展正则符号进行转义,简化了复杂模式的匹配操作。
在现代系统中,egrep 通常是 grep -E 的别名(功能完全一致),即:
egrep "pattern" file 等价于 grep -E "pattern" file
2. 与基础 grep 的核心区别
| 特性 | 基础 grep(默认,BRE模式) | egrep(或 grep -E,ERE模式) |
|---|---|---|
| 扩展正则符号支持 | 需用 \ 转义(如 \+、\{、|) |
直接使用,无需转义(如 +、{、` |
| 适用场景 | 简单匹配(单字符、基础逻辑) | 复杂匹配(多条件、分组、范围限定等) |
3. 支持的扩展正则符号
egrep 支持所有基础正则符号(如 ^、$、[]、. 等),额外支持以下扩展符号:
|:逻辑“或”,匹配多个模式中的任意一个。():分组匹配,将多个字符视为整体,可结合|使用。+:前一个字符出现 1次或多次。?:前一个字符出现 0次或1次。{n,m}:前一个字符出现 n到m次({n}表示正好n次,{n,}表示至少n次,{,m}表示至多m次)。
4. 基本语法
egrep [参数] "扩展正则模式" [文件/目录]
5. 实用示例
(1)基础扩展正则匹配
匹配“1次或多次”字符(+):
# 匹配包含连续2个及以上“5”的行(等价于 grep -E "5+" test)
egrep "5+" test
# 输出:555(假设test文件中有“555”)
匹配“固定次数”字符({}):
# 匹配“2”出现4-5次的行(test02文件内容见下方)
egrep "2{4,5}" test02
# 输出:
# 2222
# 22222
# test02 文件内容参考:
aaa
bbb
111
222
2222
22222
多模式“或”匹配(|):
# 匹配包含“reboot”或“tty2”的行
egrep "reboot|tty2" /var/log/wtmp
# 输出:
# reboot system boot 5.14.0-503.31.1. Sat Nov 16 08:00 still running
# root tty2 tty2 Sat Nov 16 08:00 - down (07:07)
(2)提取精确匹配内容(-o)
# 从网卡信息中提取所有类似IP的格式(xxx.xxx.xxx.xxx)
ip a s wlo1 | egrep -o "([0-9]{1,3}\.){3}[0-9]{1,3}"
# 输出:
# 192.168.0.102
# 192.168.0.255
# 解析:`([0-9]{1,3}\.){3}` 匹配前3段(如“192.168.0.”),最后接 `[0-9]{1,3}` 匹配第4段。
(3)反向匹配(-v)
# 过滤文件中的空行(^$)和注释行(^#)
egrep -v "^#|^$" line.txt
# 输出:
# aaa
# bbb
# ccc
# eee
# line.txt 文件内容参考:
aaa
bbb
# 注释行
#
(空行)
ccc
eee
(4)递归查找(-r)
# 递归查找当前目录下所有文件中包含“lib”的行
egrep -r "lib" ./libssh
# 输出匹配的文件名、行号及内容(如 ./libssh/config:5:import libssh)
(5)分组匹配与组合逻辑
# 匹配以“a”或“r”开头且后跟“ole”的单词(结合分组与|)
egrep "^(a|r)ole" test
# 输出:
# role
# aole