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

五、常见错误与注意事项

  1. 正则中特殊字符未转义:如.在正则中表示任意字符,匹配实际.需转义为\.(例:grep "192\.168" ips.txt)。
  2. -n-o混用:-o仅输出匹配部分,-n的行号可能无意义,需根据需求选择。
  3. 递归查找目录时遗漏-r:未加-r会将目录视为文件,导致"Is a directory"错误。
  4. 扩展正则未加-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