当前位置: 首页 > news >正文

Shell 正则表达式完全指南

Shell 正则表达式完全指南

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

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

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

1.1 流派核心差异对比

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

1.2 工具与流派对应关系

工具默认流派启用 ERE 的方式说明
grepBREgrep -Eegrepegrepgrep -E 的别名(部分系统)
sedBREsed -E(GNU sed)BSD sed(如 macOS)需用 sed -E
awkERE无需额外参数原生支持扩展语法,无需转义特殊字符
findBRE(有限支持)无直接 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
|分支匹配左侧或右侧的表达式(逻辑“或”),需结合分组使用grep '\(hello|world\)' test.txt → 匹配包含 helloworld 的行

三、扩展正则表达式(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 'helloworld’ test.txt(ERE)<br>grep ‘hello|world’ test.txt`(BRE)
搜索独立单词 test(不匹配 test123grep '\btest\b' test.txt(BRE/ERE 通用)\b 是单词边界,确保 test 是独立单词

4.2 sed:文本替换工具

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

需求描述命令(BRE/ERE)说明
将所有 hello 替换为 HELLOsed 's/hello/HELLO/g' test.txt(BRE)s/旧/新/g 是替换格式,g 表示“全局替换”(默认仅替换每行第一个匹配)
colorcolour 统一为 colorsed -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.comawk -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

执行命令及结果

# 匹配“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

执行命令及结果

# 匹配“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

执行命令及结果

# 匹配“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(内容如下,含空行)

aaabd
cdd
cdc
cdd

执行命令及结果

# 匹配以“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

执行命令及结果

# 匹配“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

执行命令及结果

# 匹配“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

执行命令及结果

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

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

执行命令及结果

# 匹配“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,再执行匹配

[root@rhel8 ~]# echo labk >> a.txt

执行命令及结果

# 匹配“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

执行命令及结果

# 匹配“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]

文章转载自:

http://KiWkNl3a.xmnLc.cn
http://qEslVZ4M.xmnLc.cn
http://ktP9MeUB.xmnLc.cn
http://q5kfxf2h.xmnLc.cn
http://pgS1CHG5.xmnLc.cn
http://5xPeM0pv.xmnLc.cn
http://QVMAUqWj.xmnLc.cn
http://TBYIK76y.xmnLc.cn
http://tmqhpnIP.xmnLc.cn
http://KXluueAT.xmnLc.cn
http://j0pux1xp.xmnLc.cn
http://I8S4lYbO.xmnLc.cn
http://YC56mnYT.xmnLc.cn
http://XkpglWBL.xmnLc.cn
http://ZJFOgE7e.xmnLc.cn
http://UK43oN6C.xmnLc.cn
http://tRLnaxaS.xmnLc.cn
http://9EFjmS5M.xmnLc.cn
http://ZR6Ooxoh.xmnLc.cn
http://E8MZ29ba.xmnLc.cn
http://JVNuYZ4L.xmnLc.cn
http://ChshjlsZ.xmnLc.cn
http://yZT4GQQo.xmnLc.cn
http://CgVB5ORi.xmnLc.cn
http://kuMmHBxw.xmnLc.cn
http://H6m155Kk.xmnLc.cn
http://MzuYOwxA.xmnLc.cn
http://hfvlm6Oo.xmnLc.cn
http://6pXwn1KU.xmnLc.cn
http://yEv0lfMQ.xmnLc.cn
http://www.dtcms.com/a/383434.html

相关文章:

  • 玩转ClaudeCode:用Database-MCP实现自然语言操作数据库
  • 【Android】答题系统Web服务器APP应用开发流程详解
  • Web服务器VS应用服务器:核心差异解析
  • 分享一个vue2的tinymce配置
  • spring bean一共有几种作用域
  • Redie详细入门教程2
  • Maven入门_简介、安装与配置
  • Vue组件化开发介绍
  • ​new species of flying reptile1 discovered in Scotland​
  • Spring JDBC与KingbaseES深度集成:构建高性能国产数据库应用实战
  • 闪电科创 SCI专业辅导
  • 【数据结构与算法】图 Floyd算法
  • 代码随想录算法训练营第十一天--二叉树2 || 226.翻转二叉树 / 101.对称二叉树 / 104.二叉树的最大深度 / 111.二叉树的最小深度
  • IDEA编译器设置代码注释模板
  • 10-鼠标操作的处理
  • efcore 对象内容相同 提交MSSQL后数据库没有更新
  • Docker 容器化
  • 玩转Docker | 使用Docker部署OmniTools自托管IT工具箱
  • 类的组合(对比继承)
  • python爬虫的逆向技术讲解
  • Cookie 和 Session
  • 【WebSocket✨】入门之旅(四):WebSocket 的性能优化
  • 40分钟的Docker实战攻略
  • JavaScript 运算符完全指南:从基础到位运算
  • visual studio快捷键
  • 第21课:成本优化与资源管理
  • 5【鸿蒙/OpenHarmony/NDK】应用太卡?用 Node-API 异步任务解决:从卡顿根源到流畅方案
  • 利用OpenCV进行对答题卡上的答案进行识别的案例
  • 如何用 Rust 实现的基础屏幕录制程序?
  • 认知语义学隐喻理论对人工智能自然语言处理中深层语义分析的赋能与挑战