Shell 正则表达式完全指南

Shell 正则表达式完全指南

正则表达式(Regular Expression,简称 Regex)是一种用于匹配、查找和替换文本的模式语言。在 Shell 环境中,正则表达式被广泛应用于 grepsedawkfind 等工具,是文本处理和自动化脚本编写的核心技能。本文档将从基础到进阶,全面讲解 Shell 正则表达式的语法、流派差异及实战应用。

一、Shell 正则表达式的两大流派

Shell 工具对正则表达式的支持分为 基础正则表达式(Basic Regular Expression,BRE)扩展正则表达式(Extended Regular Expression,ERE) 两大流派,核心区别在于特殊字符是否需要转义,不同工具对流派的支持不同,需重点区分。

1.1 流派核心差异对比

特性 基础正则表达式(BRE) 扩展正则表达式(ERE)
支持工具 grep(默认)、sed(默认)、vi grep -E/egrepsed -Eawk
特殊字符转义要求 ?+{}()、` ` 需转义
核心场景 简单匹配(如固定字符串、单字符通配) 复杂匹配(如重复次数、分支、分组)

1.2 工具与流派对应关系

工具 默认流派 启用 ERE 的方式 说明
grep BRE grep -Eegrep egrepgrep -E 的别名(部分系统)
sed BRE sed -E(GNU sed) BSD sed(如 macOS)需用 sed -E
awk ERE 无需额外参数 原生支持扩展语法,无需转义特殊字符
find BRE(有限支持) 无直接 ERE 选项 仅支持基础元字符,复杂匹配需结合 grep

二、基础正则表达式(BRE)语法

BRE 是 Shell 工具的默认正则流派,语法简洁,适用于简单文本匹配。以下是 BRE 的核心语法,按功能分类说明。

2.1 锚定符:定位匹配位置

锚定符不匹配具体字符,仅限定匹配内容在文本中的位置,是精准匹配的关键。

符号 名称 功能说明 示例
^ 行首锚定 匹配以指定内容开头的(仅匹配行首第一个字符后的数据) grep '^root' /etc/passwd → 匹配所有以 root 开头的行
$ 行尾锚定 匹配以指定内容结尾的(仅匹配行尾最后一个字符前的数据) grep 'bash$' /etc/passwd → 匹配所有以 bash 结尾的行
^$ 空行匹配 匹配无任何字符的空行(^ 行首 + $ 行尾,中间无内容) grep '^$' test.txt → 统计 test.txt 中的空行数
\b 单词边界 匹配单词的边界(单词指由字母、数字、下划线组成的连续字符) grep '\bhello\b' test.txt → 仅匹配独立的单词 hello(不匹配 helloworld
\B 非单词边界 匹配非单词边界(与 \b 相反) grep '\Bhello\B' test.txt → 匹配 ohellow 中的 hello

2.2 字符匹配符:匹配单个字符

字符匹配符用于匹配单个字符,可灵活指定允许的字符范围或类型。

符号 名称 功能说明 示例
. 任意字符 匹配除换行符(\n)外的任意一个字符 grep 'h.llo' test.txt → 匹配 hellohallohxllo
[] 字符集合 匹配集合中的任意一个字符 (集合内字符无序,支持 - 表示范围) grep 'h[aei]llo' test.txt → 仅匹配 hellohallohillo
[^] 否定字符集 匹配不在集合中的任意一个字符^[] 内表示否定) grep 'h[^aei]llo' test.txt → 匹配 hxllohllo(不匹配 hello
[a-z] 小写字母集 匹配任意一个小写英文字母(az,需按 ASCII 顺序) grep '[a-z]' test.txt → 匹配包含小写字母的行
[A-Z] 大写字母集 匹配任意一个大写英文字母 grep '[A-Z]' test.txt → 匹配包含大写字母的行
[0-9] 数字集 匹配任意一个数字(等价于 [0123456789] grep '[0-9]' test.txt → 匹配包含数字的行
[a-zA-Z0-9_] 单词字符集 匹配任意一个字母、数字或下划线(等价于 \w,但 BRE 中 \w 兼容性较差) grep '[a-zA-Z0-9_]' test.txt → 匹配包含单词字符的行

2.3 重复匹配符:匹配多个连续字符

重复匹配符用于指定前一个字符或子表达式的重复次数 ,是简化多字符匹配的核心。注意:BRE 中 ?+{} 需转义

符号 名称 功能说明 示例
* 零次或多次 匹配前一个字符0次或任意多次(尽可能多匹配,贪婪模式) grep 'ho*' test.txt → 匹配 hhohoohooo
\? 零次或一次 匹配前一个字符0次或1次(可选字符) grep 'colou\?r' test.txt → 匹配 color(美式)和 colour(英式)
\+ 一次或多次 匹配前一个字符1次或任意多次(至少1次) grep 'a\+' test.txt → 匹配 aaaaaa(不匹配空)
\{n\} 恰好n次 匹配前一个字符恰好n次 grep 'a\{3\}' test.txt → 仅匹配 aaa(3个连续 a
\{n,\} 至少n次 匹配前一个字符至少n次 grep 'a\{2,\}' test.txt → 匹配 aaaaaaaaa
\{n,m\} n到m次 匹配前一个字符n次到m次(包含n和m) grep 'a\{2,4\}' test.txt → 匹配 aaaaaaaaa(不匹配 aaaaaa

2.4 分组与分支(BRE 有限支持)

BRE 对分组和分支的支持较弱,需通过转义实现,主要用于复杂逻辑匹配。

符号 名称 功能说明 示例
\( \) 分组 将括号内的内容视为一个整体(子表达式),用于重复或引用 grep '\(ab\)*' test.txt → 匹配 abababababab
` ` 分支 匹配左侧或右侧的表达式(逻辑"或"),需结合分组使用

三、扩展正则表达式(ERE)语法

ERE 是 BRE 的扩展,简化了特殊字符的使用(无需转义),支持更复杂的匹配逻辑,是 grep -Esed -Eawk 的默认语法。

3.1 ERE 与 BRE 的核心区别

ERE 本质是 BRE 的"语法糖",核心差异在于特殊字符无需转义,具体对比如下:

功能 BRE 语法(需转义) ERE 语法(无需转义) 示例(匹配 2-4 个 a
零次或一次 \? ? BRE:grep 'a\?' test.txt ERE:grep -E 'a?' test.txt
一次或多次 \+ + BRE:grep 'a\+' test.txt ERE:grep -E 'a+' test.txt
重复次数 \{n,m\} {n,m} BRE:grep 'a\{2,4\}' test.txt ERE:grep -E 'a{2,4}' test.txt
分组 \( \) ( ) BRE:grep '\(ab\)*' test.txt ERE:grep -E '(ab)*' test.txt
分支 ` ` `

3.2 ERE 专属高级语法

ERE 除简化 BRE 语法外,无新增核心符号,但结合工具(如 awk)可实现更灵活的应用,例如:

  • 分组引用 :在 sed -Eawk 中,可通过 \1\2 引用分组内容(\1 表示第一个分组)。
    示例:sed -E 's/(hello)/\1 world/' test.txt → 将 hello 替换为 hello world

四、Shell 工具正则实战案例

掌握语法后,需结合工具场景灵活应用。以下是 grepsedawk 的高频实战案例。

4.1 grep:文本搜索工具

grep 是最常用的正则匹配工具,核心功能是"搜索符合模式的行",支持 BRE(默认)和 ERE(-E)。

需求描述 命令(BRE/ERE) 说明
搜索以 # 开头的注释行(忽略空行) grep '^#' /etc/httpd/conf/httpd.conf ^# 匹配行首的 #,排除非注释行
搜索包含 1-3 个数字的行 grep -E '[0-9]{1,3}' test.txt(ERE) grep '[0-9]\{1,3\}' test.txt(BRE) ERE 无需转义 {},更简洁
搜索包含 helloworld 的行 `grep -E 'hello world' test.txt(ERE)<br>grep 'hello|world' test.txt`(BRE)
搜索独立单词 test(不匹配 test123 grep '\btest\b' test.txt(BRE/ERE 通用) \b 是单词边界,确保 test 是独立单词

4.2 sed:文本替换工具

sed 是流编辑器,核心功能是"按模式修改文本",默认使用 BRE,-E 启用 ERE。

需求描述 命令(BRE/ERE) 说明
将所有 hello 替换为 HELLO sed 's/hello/HELLO/g' test.txt(BRE) s/旧/新/g 是替换格式,g 表示"全局替换"(默认仅替换每行第一个匹配)
colorcolour 统一为 color sed -E 's/colou?r/color/g' test.txt(ERE) u? 匹配 u 0 次或 1 次,同时覆盖美式和英式拼写
删除所有空行 sed '/^$/d' test.txt(BRE) /^$/ 匹配空行,d 表示"删除该行"
在每行开头添加 [INFO] 前缀 sed 's/^/[INFO] /' test.txt(BRE) ^ 匹配行首,在开头插入 [INFO]

4.3 awk:文本分析工具

awk 是强大的文本分析工具,原生支持 ERE,核心功能是"按行处理文本字段"(默认以空格分割字段,$1 表示第一个字段,$0 表示整行)。

需求描述 命令(ERE) 说明
提取 /etc/passwd 中 UID 为 0 的用户(root 及等效用户) awk -F ':' '$3 == 0 {print $1}' /etc/passwd -F ':' 指定分隔符为 :$3 是 UID 字段,匹配 UID=0 并打印用户名($1
统计日志中包含 ERROR 的行数 awk '/ERROR/ {count++} END {print count}' log.txt /ERROR/ 用 ERE 匹配包含 ERROR 的行,count++ 计数,END 块输出结果
提取 URL 中的域名(如 https://www.baidu.com/pathwww.baidu.com awk -F '[/:]' '/^https:\/\// {print $4}' urls.txt -F '[/:]' 指定分隔符为 /:$4 对应域名字段

五、常见问题与注意事项

5.1 转义字符的坑

  • Shell 转义 vs 正则转义 :Shell 会先解析命令中的特殊字符(如 $*\),再将结果传递给正则工具。若需匹配正则中的特殊字符(如 $ 行尾锚定),需避免被 Shell 解析。

    解决方案:用单引号 包裹正则表达式(Shell 不解析单引号内的字符),例如 grep '^hello$' test.txt(正确匹配整行 hello),而非双引号(grep "^hello$" test.txt 可能被 Shell 干扰)。

  • 工具差异 :BSD sed(macOS)和 GNU sed(Linux)对转义的处理略有不同,例如 macOS 中 sed 需用 sed -E 启用 ERE,而 Linux 中 sed -rsed -E 等价。

5.2 贪婪匹配与非贪婪匹配

Shell 正则默认是贪婪模式 (尽可能匹配最长的内容),例如 grep 'a.*b' test.txt 会匹配 a1b2b 中的 a1b2b(而非 a1b)。
注意 :Shell 正则(BRE/ERE)不支持非贪婪模式(如 .*?),若需非贪婪匹配,需使用 perlgrep -P(部分系统支持,启用 Perl 兼容正则),例如 grep -P 'a.*?b' test.txt

5.3 空行与空白行的区别

  • 空行:无任何字符(包括空格、制表符),正则为 ^$
  • 空白行:包含空格或制表符(\t),正则为 ^[[:space:]]*$[[:space:]] 匹配任意空白字符,* 表示零次或多次)。
    示例:grep '^[[:space:]]*$' test.txt → 匹配空行和空白行。

六、总结

Shell 正则表达式是文本处理的核心工具,需重点掌握:

  1. 流派区分 :BRE(默认,需转义特殊字符)和 ERE(-E 启用,无需转义)。
  2. 核心语法 :锚定符(^$)、字符匹配符(.[])、重复匹配符(*{n,m})、分组与分支(()|)。
  3. 工具实战grep 搜索、sed 替换、awk 字段分析,结合具体场景选择合适工具。

通过多练习文本处理场景(如日志分析、配置文件修改、数据提取),可快速掌握正则表达式的灵活应用。

正则表达式练习题

2. 基础正则元字符实战案例(基于grep工具)

案例1:*匹配前面一个字符0次或多次

操作文件a.txt(内容如下)

复制代码
lk
lok
look
loook
looooook
loooooaaak
looooooook
abbbbcd
abbbbcd666
ooooloooook
oooooolk
aoblck

执行命令及结果

bash 复制代码
# 匹配"lo"后接0个或多个"o"再接"k"(即"lok""look""loook"等,排除"lk")
[root@rhel8 ~]# grep "loo*k" a.txt
lok
look
loook
looooook
looooooook
ooooloooook

# 匹配"l"后接0个或多个"o"再接"k"(包含"lk""lok""look"等)
[root@rhel8 ~]# grep "lo*k" a.txt
lk
lok
look
loook
looooook
looooooook
ooooloooook
oooooolk
案例2:.匹配除\n之外的任意一个字符

操作文件 :同案例1的a.txt

执行命令及结果

bash 复制代码
# 匹配"lo"后接任意字符(0个或多个)再接"k"(包含中间有其他字符的情况,如"loooooaaak")
[root@rhel8 ~]# grep "lo.*k" a.txt 
lok
look
loook
looooook
loooooaaak
looooooook
ooooloooook

# 重复执行上述命令,结果一致
[root@rhel8 ~]# grep "lo.*k" a.txt 
lok
look
loook
looooook
loooooaaak
looooooook
ooooloooook

# 匹配"lo"后接1个任意字符再接"k"(仅"look"符合)
[root@rhel8 ~]# grep "lo.k" a.txt
look

# 匹配"l"后接2个任意字符再接"k"(仅"look"符合,"l"+"oo"+"k")
[root@rhel8 ~]# grep "l..k" a.txt
look
案例3:\{n\}\{n,\}\{n,m\}匹配字符重复次数

操作文件 :同案例1的a.txt

执行命令及结果

bash 复制代码
# 匹配"lo"后接2个"o"再接"k"(即"look","o"恰好出现2次)
[root@rhel8 ~]# grep "lo\{2\}k" a.txt 
look

# 匹配"lo"后接3个"o"再接"k"(即"loook","o"恰好出现3次)
[root@rhel8 ~]# grep "lo\{3\}k" a.txt 
loook

# 匹配"lo"后接3个及以上"o"再接"k"("loook""looooook"等)
[root@rhel8 ~]# grep "lo\{3,\}k" a.txt 
loook
looooook
looooooook
ooooloooook

# 匹配"lo"后接3-5个"o"再接"k"(仅"loook""ooooloooook"符合)
[root@rhel8 ~]# grep "lo\{3,5\}k" a.txt 
loook
ooooloooook
案例4:^$匹配字符串首尾位置

操作文件b.txt(内容如下,含空行)

复制代码
aa

abd
cdd
cdc
cdd

执行命令及结果

bash 复制代码
# 匹配以"c"开头的字符串("cdd""cdc")
[root@rhel8 ~]# grep "^c" b.txt 
cdd
cdc
cdd

# 匹配以"d"结尾的字符串("abd""cdd")
[root@rhel8 ~]# grep "d$" b.txt 
abd
cdd
cdd

# 匹配空行(输出结果为空行,对应文件中的空行)
[root@rhel8 ~]# grep "^$" b.txt 

[root@rhel8 ~]# 
案例5:[list][^list]匹配指定/非指定字符

操作文件c.txt(内容如下)

复制代码
lok
lo12k
lo1k
loAk
loBk
look
loak
lodk
abcd
1234

执行命令及结果

bash 复制代码
# 匹配"lo"后接字母(a-z、A-Z)或数字(0-9)再接"k"(排除"lok""lo12k")
[root@rhel8 ~]# grep "lo[a-zA-Z0-9]k" c.txt 
lo1k
loAk
loBk
look
loak
lodk

# 匹配"lo"后接"A""B""o"中的任意一个字符再接"k"("loAk""loBk""look")
[root@rhel8 ~]# grep "lo[ABo]k" c.txt 
loAk
loBk
look

# 匹配"lo"后接非字母(a-z、A-Z)的字符再接"k"(仅"lo1k"符合)
[root@rhel8 ~]# grep "lo[^a-zA-Z]k" c.txt 
lo1k

# 匹配包含非字母(a-z、A-Z)的字符串("lo12k""lo1k""1234")
[root@rhel8 ~]# grep "[^a-zA-Z]" c.txt 
lo12k
lo1k
1234

三、扩展正则

扩展正则是基础正则的补充,支持更多灵活的匹配逻辑,核心元字符及功能如下:

元字符 功能说明 示例
+ 匹配前面一个字符出现1次或多次(比*更严格,至少1次) lo+k(匹配lo后接1个或多个o再接k,如loklookloook
? 匹配前面一个字符出现0次或1次(可选字符匹配) lo?k(匹配l后接0个或1个o再接k,即lklok
() 将括号中的字符串作为一个整体(分组匹配) l(oo)+k(匹配l后接1个或多个"oo"整体再接k,如looklooook
` ` 以"或"逻辑匹配多个字符串(分支匹配)
{} 为可重复的正则表达式指定重复次数(间隔匹配),功能同基础正则的\{n\}/\{n,\}/\{n,m\},但无需转义 lo{2}k(匹配lo后接2个o再接k)、lo{2,}k(匹配lo后接2个及以上o再接k)、lo{2,3}k(匹配lo后接2-3个o再接k

2. 扩展正则元字符实战案例(基于egrep工具)

案例1:+匹配前面一个字符1次以上

操作文件 :同基础正则案例1的a.txt

执行命令及结果

bash 复制代码
# 匹配"lo"后接1个或多个"o"再接"k"(排除"lk",包含"lok""look"等)
[root@rhel8 ~]# egrep "lo+k" a.txt 
lok
look
loook
looooook
looooooook
ooooloooook
案例2:?匹配前面一个字符0次或1次

操作文件 :同基础正则案例1的a.txt

执行命令及结果

bash 复制代码
# 匹配"l"后接0个或1个"o"再接"k"(仅"lk""lok""oooooolk"符合)
[root@rhel8 ~]# egrep "lo?k" a.txt 
lk
lok
oooooolk
案例3:()将括号中的字符串作为整体匹配

操作文件 :同基础正则案例1的a.txt

执行命令及结果

bash 复制代码
# 匹配"l"后接1个或多个"oo"整体再接"k"("look""looooook""looooooook",即"oo"重复1次、2次、3次)
[root@rhel8 ~]# egrep "l(oo)+k" a.txt 
look
looooook
looooooook
案例4:|以"或"逻辑匹配多个字符串

操作文件 :先向a.txt追加内容labk,再执行匹配

bash 复制代码
[root@rhel8 ~]# echo labk >> a.txt

执行命令及结果

bash 复制代码
# 匹配"l"后接1个或多个"oo"整体,或1个或多个"ab"整体,再接"k"("look""looooook""looooooook""labk")
[root@rhel8 ~]# egrep "l(oo|ab)+k" a.txt 
look
looooook
looooooook
labk
案例5:{}指定字符重复次数

操作文件 :同基础正则案例1的a.txt(已追加labk

执行命令及结果

bash 复制代码
# 匹配"lo"后接3个"o"再接"k"(仅"loook"符合)
[root@rhel8 ~]# egrep "lo{3}k" a.txt 
loook

# 匹配"lo"后接3个及以上"o"再接"k"("loook""looooook""looooooook""ooooloooook")
[root@rhel8 ~]# egrep "lo{3,}k" a.txt 
loook
looooook
looooooook
ooooloooook

# 匹配"lo"后接3-5个"o"再接"k"(仅"loook""ooooloooook"符合)
[root@rhel8 ~]# egrep "lo{3,5}k" a.txt 
loook
ooooloooook

四、特殊的字符组

特殊字符组是基础/扩展正则中预设的"字符集合缩写",简化对特定类型字符的匹配,适用于所有支持正则的Linux工具,具体如下:

特殊字符组 描述
[[:alpha:]] 匹配任意字母字符(大写A-Z或小写a-z)
[[:alnum:]] 匹配任意字母数字字符(0-9、A-Z、a-z)
[[:blank:]] 匹配空格( )或Tab键(\t
[[:digit:]] 匹配0-9之间的任意一个数字(等价于[0-9]
[[:lower:]] 匹配小写字母字符(a-z,等价于[a-z]
[[:print:]] 匹配任意可打印字符(包括字母、数字、标点、空格等,排除不可见字符如\n
[[:punct:]] 匹配任意标点符号(如!@#$,.等)
[[:space:]] 匹配任意空白字符(包括空格、Tab键、换行符\n、换页符\f、垂直制表符\v、回车符\r
[[:upper:]] 匹配任意大写字母字符(A-Z,等价于[A-Z]
相关推荐
Mrliu__2 小时前
Python高级技巧(六):正则表达式
开发语言·python·正则表达式
AhoJustLikeU2 小时前
萌新学习正则表达式日志
正则表达式
禹凕3 小时前
MySQL——基础知识(正则表达式)
数据库·mysql·正则表达式
Jerry_Gao9211 天前
【CTF】【ez-rce】无字母数字绕过正则表达式
正则表达式·php·ctf
烤麻辣烫2 天前
正则表达式快速掌握
前端·javascript·学习·正则表达式·html
jz_ddk5 天前
[指南] UltraEdit正则表达式完全指南
正则表达式·ultraedit
爱上妖精的尾巴9 天前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
观无11 天前
正则表达式原理
服务器·数据库·正则表达式
怣5012 天前
MySQL正则表达式模糊查询完全指南:让数据查找更智能
数据库·mysql·正则表达式