Linux 正则表达式
-
定义:正则表达式是一种pattern(模式),用于与待搜索字符串匹配,以查找一个或多个目标字符串。
-
组成:自成体系,由两类字符构成
-
普通字符:未被显式指定为元字符的所有可打印和不可打印字符,包括大小写字母、数字、标点符号及其他符号。
-
元字符:除普通字符之外的字符。
-
-
应用范围:被多种工具(如 vim、grep、less 等)和编程语言(如 Perl、Python、C 等)所使用。
-
正则表达式分类:
- 普通正则表达式
- 扩展正则表示,支持更多的元字符。
环境准备
bash
[lth@controller ~ 18:31:13]$ vim words
cat
category
acat
concatenate
dog
字符集
[...]
匹配 [...] 中的任意一个字符。
bash
[lth@controller ~ 18:32:14]$ echo cbt >> words
[lth@controller ~ 18:32:20]$ echo c1t >> words
[lth@controller ~ 18:32:24]$ cat words | grep 'c[ab]t'
cat
category
acat
concatenate
cbt
[a-z] [A-Z] [0-9]
这三个是正则表达式中常用的字符类(字符范围匹配),用于匹配指定范围内的单个字符:
-
[a-z],匹配所有小写字母。 -
[A-Z],匹配所有大写字母。 -
[0-9],匹配所有数字。 -
它们常结合量词使用,如
[0-9]+可匹配一个或多个连续数字。-
[0-9]+是正则表达式中常用的组合模式,由两部分构成:[0-9]:表示匹配任意单个数字(0-9 中的一个)+:元字符,作为量词,表示 "匹配前面的元素一次或多次"
结合起来,
[0-9]+的含义是:匹配一个或多个连续的数字。
-
bash
[lth@controller ~ 18:33:00]$ cat words | grep 'c[a-z]t'
cat
category
acat
concatenate
cbt
[lth@controller ~ 18:33:06]$ echo cCt >> words
[lth@controller ~ 18:33:10]$ cat words | grep 'c[A-Z]t'
cCt
[lth@controller ~ 18:33:13]$ cat words | grep 'c[0-9]t'
c1t
[lth@controller ~ 18:33:17]$ cat words | grep 'c[a-z0-9]t'
cat
category
acat
concatenate
cbt
c1t
[lth@controller ~ 18:33:21]$ cat words | grep 'c[a-zA-Z0-9]t'
cat
category
acat
concatenate
cbt
c1t
cCt
# 要想匹配-符号,将改符号写在第一个位置
[lth@controller ~ 18:33:26]$ echo c-t >> words
[lth@controller ~ 18:33:30]$ cat words | grep 'c[-a-zA-Z0-9]t'
cat
category
acat
concatenate
cbt
c1t
cCt
c-t
[^...]
否定字符类,匹配除 [...] 中包含的所有字符以外的任意单个字符。
- 例:
c[^ab]t匹配 "c" 开头、"t" 结尾,且中间不是 "a" 或 "b" 的字符串(如匹配 "c1t") - 注意:
^仅在字符类开头时表示否定,若在中间则视为普通字符(如c[a^b]t会匹配 "cat" 或 "cbt" 等)
bash
[lth@controller ~ 18:45:01]$ cat words | grep 'c[^ab]t'
c1t
# ^放中间会被当做普通字符
[lth@controller ~ 18:45:08]$ cat words | grep 'c[a^b]t'
cat
category
acat
concatenate
cbt
.
匹配除换行符(\n、\r)之外的任意单个字符,相等于\[^\n\r]。
- 例:
c.t可匹配 "cat"、"cbt"、"c1t"、"c-t" 等(只要中间是单个非换行字符)
bash
[lth@controller ~ 18:45:35]$ cat words | grep 'c.t'
cat
category
acat
concatenate
cbt
c1t
cCt
c-t
\
将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。
-
例, 'n' 匹配字符 'n'。
\n匹配换行符。序列\\匹配\,而\(则匹配(。 -
例:
c\.t专门匹配 "c.t"(将.转义为普通点号) -
注意:对普通字符(如
a)加\虽可能匹配,但不建议这样使用
bash
[lth@controller ~ 18:45:55]$ echo c.t >> words
[lth@controller ~ 18:46:10]$ cat words | grep 'c\.t'
c.t
# 匹配普通字符,虽然可以匹配,但强烈建议不要在前面加\
[lth@controller ~ 18:46:14]$ cat words | grep 'c\at'
cat
category
acat
concatenate
|
| 符号是扩展正则中的 "或" 操作符,用于匹配两项中的任意一项。要匹配 |,请使用 \|。
- 需配合
egrep或grep -E使用 - 例:
cat|dog可同时匹配包含 "cat" 或 "dog" 的字符串
bash
# 使用egrep或者grep -E 匹配
[lth@controller ~ 18:48:36]$ cat words | egrep 'cat|dog'
cat
category
acat
concatenate
dog
# 或者
[lth@controller ~ 18:48:41]$ cat words | grep -E 'cat|dog'
cat
category
acat
concatenate
dog
非打印字符
在正则表达式中,非打印字符指的是那些不在屏幕上直接显示的字符(如换行符、制表符等)。它们在文本处理中非常重要,常需要通过特殊转义序列来匹配。以下是常见的非打印字符及其正则表示:
| 字符 | 描述 |
|---|---|
| \cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。 |
| \f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
| \n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
| \r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
| \s | 匹配任何空白字符 ,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。 |
| \S | 匹配任何非空白字符 。等价于 [^ \f\n\r\t\v]。 |
| \w | 匹配字母、数字、下划线。等价于 [A-Za-z0-9_] |
| \W | 匹配任何非单词字符。等价于[^A-Za-z0-9_] |
| \t | 匹配一个制表符。等价于 \x09 和 \cI。 |
| \v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
grep 命令支持
\w、\W、\s、\S。
定位符
^
匹配行首位置。
bash
[lth@controller ~ 18:51:15]$ cat words | grep '^cat'
cat
category
$
匹配行末位置。
-
作用:限定匹配内容必须出现在行的结尾
-
示例 1:
bash# 查找以 "cat" 结尾的行,匹配到 "cat"(整行都是 cat)和 "acat"(行尾是 cat) [lth@controller ~ 18:54:57]$ cat words | grep 'cat$' cat acat -
示例 2:
bash# `^`匹配行首,`$`匹配行尾,组合起来只匹配整行内容恰好是 "cat"的行。 [lth@controller ~ 18:55:10]$ cat words | grep '^cat$' cat
\b
匹配一个单词边界。
-
作用:匹配单词与非单词字符之间的位置(如字母与空格、标点、行首 / 行尾的交界处)
-
示例 1:
bash# `\bcat`匹配以 "cat" 开头的单词,包括: # - 单独的 "cat"(行首单词) # - "category"(以 cat 开头的长单词) # - "hello cat"(空格后的 cat 单词) [lth@controller ~ 18:58:09]$ cat words | grep '\bcat' cat category hello cat -
示例 2:
bash# `cat\b`匹配以 "cat" 结尾的单词,包括: # - 单独的 "cat"(行尾单词) # - "acat"(以 cat 结尾的单词) # - "hello cat"(空格后的 cat 单词) [lth@controller ~ 18:58:11]$ cat words | grep 'cat\b' cat acat hello cat -
示例 3:
bash# `\bcat\b`只匹配独立的 "cat" 单词(前后都是单词边界),不匹配包含 cat 的长单词(如 category、acat) [lth@controller ~ 18:58:19]$ cat words | grep '\bcat\b' cat hello cat
\B
非单词边界匹配。
-
作用:匹配不在单词边界的位置(即字符之间是连续的单词字符,如字母与字母之间)
-
示例:
bash# '\Bcat'匹配 "cat" 前面不是单词边界的情况,即 "cat" 前面是其他字母: # - "acat" 中 "cat" 前面是 "a"(非边界) # - "concatenate" 中包含 "cat" 且前面是其他字母 [lth@controller ~ 19:03:48]$ cat words | grep '\Bcat' acat concatenate
\< 和 \>
-
作用:
\<匹配单词左边界(等同于\b),\>匹配单词右边界(等同于\b),是部分工具(如 grep)支持的扩展表示 -
示例 1:
bash# `\<cat`与`\bcat`效果相同,匹配以 "cat" 开头的单词 [lth@controller ~ 19:05:57]$ cat words | grep '\<cat' cat category hello cat -
示例 2:
bash# `cat\>`与`cat\b`效果相同,匹配以 "cat" 结尾的单词 [lth@controller ~ 19:06:41]$ cat words | grep 'cat\>' cat acat hello cat
限定次数
*
匹配前面的子表达式任意次数。
-
作用:允许前面的元素出现 0 次、1 次或多次
-
示例:
bash# do*g 中 o* 表示 "o 可以出现任意次",所以包含 0 个 o(dg)、1 个 o(dog)、2 个 o(doog)的字符串都能匹配。 [lth@controller ~ 19:09:39]$ echo dg >> words [lth@controller ~ 19:09:42]$ echo doog >> words [lth@controller ~ 19:09:47]$ cat words | grep 'do*g' dog # 匹配:d + o(1次) + g dg # 匹配:d + o(0次) + g doog # 匹配:d + o(2次) + g
+
+ 是扩展表达式元字符,匹配前面的子表达式一次以上次数 。(扩展表达式,需用egrep或grep -E)
-
作用:要求前面的元素至少出现 1 次
-
示例:
bash# do+g 中 o+ 表示 "o 至少出现 1 次",所以排除了不含 o 的dg。 [lth@controller ~ 19:11:40]$ cat words | egrep 'do+g' dog # 匹配:o出现1次 doog # 匹配:o出现2次
?
? 是扩展表达式元字符,匹配前面的子表达式一次以下次数。
-
作用:允许前面的元素最多出现 1 次
-
示例:
bash# do?g 中 o? 表示 "o 最多出现 1 次",所以排除了 o 出现 2 次的doog。 [lth@controller ~ 19:11:57]$ cat words | egrep 'do?g' dog # 匹配:o出现1次 dg # 匹配:o出现0次
{n}
{} 是扩展表达式元字符,用于匹配特定次数。例如:{n},配置n次。
-
作用:精确指定前面元素的出现次数
-
示例:
bash# do{2}g 表示 "o 必须出现且仅出现 2 次",所以只匹配doog。 [lth@controller ~ 19:12:40]$ cat words | egrep 'do{2}g' doog # 匹配:o恰好出现2次
{m,n}
{m,n},是扩展表达式元字符,用于匹配次数介于m-n之间。
-
作用:限定前面元素出现次数的范围(包含 m 和 n)
-
示例:
bash# do{2,3}g 表示 "o 出现 2 次或 3 次",所以排除了 o 出现 4 次的doooog。 [lth@controller ~ 19:14:29]$ echo dooog >> words # o出现3次 [lth@controller ~ 19:14:31]$ echo doooog >> words # o出现4次 [lth@controller ~ 19:14:35]$ cat words | egrep 'do{2,3}g' doog # o出现2次(在2-3范围内) dooog # o出现3次(在2-3范围内)
{m,}
{m,},是扩展表达式元字符,匹配前面的子表达式m次以上次数。
-
作用:前面的元素出现次数不小于 m
-
示例:
bash# do{2,}g 表示 "o 至少出现 2 次",所以包含 2 次、3 次、4 次 o 的字符串都匹配。 [lth@controller ~ 19:17:34]$ cat words | egrep 'do{2,}g' doog # o出现2次 dooog # o出现3次 doooog # o出现4次
{,n}
{,n},是扩展表达式元字符,匹配前面的子表达式n次以下次数。
-
作用:前面的元素出现次数不大于 n
-
示例:
bash# do{,3}g 表示 "o 最多出现 3 次",所以排除了 o 出现 4 次的doooog。 [lth@controller ~ 19:18:17]$ cat words | egrep 'do{,3}g' dog # o出现1次 doog # o出现2次 dg # o出现0次 dooog # o出现3次
()
标记一个子表达式。
-
作用:将多个字符视为一个整体,配合限定符使用
-
示例:
bash[lth@controller ~ 19:19:33]$ echo dogdog >> words # "dog"出现2次 [lth@controller ~ 19:19:35]$ echo dogdogdog >> words # "dog"出现3次 [lth@controller ~ 19:19:41]$ echo dogdogdogdog >> words # "dog"出现4次 # 匹配"dog"出现2-3次的字符串 # (dog){2,3} 中,(dog) 将 "dog" 视为一个整体,{2,3} 限定这个整体出现 2-3 次,因此匹配包含 2 个或 3 个连续 "dog" 的字符串。 [lth@controller ~ 19:19:47]$ cat words | egrep '(dog){2,3}' dogdog dogdogdog dogdogdogdog # 包含"dog"3次的部分(前3个"dog") # 匹配"dog"出现至少2次的字符串 [lth@controller ~ 19:19:56]$ cat words | egrep '(dog){2,}' dogdog dogdogdog dogdogdogdog
这些限定符用于精确控制字符或子表达式的出现次数,是正则表达式中实现灵活匹配的核心功能,其中+、?、{}、()属于扩展正则,需用egrep或grep -E才能生效。
反向引用
反向引用是正则表达式中通过圆括号()捕获子匹配(存储到临时缓冲区),再用\N(N为 1-99 的数字,代表缓冲区编号)引用已捕获内容的机制。捕获的子匹配按从左到右顺序存储,\N用于重复调用对应缓冲区的内容,实现对重复模式的匹配。
示例 1:引用首个捕获组
bash
[lth@controller ~ 19:28:13]$ echo 'laoma laoniu laohu laoma laoniu laohu' | \
> egrep -o '(laoma) (laoniu).*\1'
# 过滤结果如下
laoma laoniu laohu laoma
- 解析:
(laoma)是第 1 个捕获组,匹配字符串laoma并存储到缓冲区 1;(laoniu)是第 2 个捕获组,匹配laoniu;.*匹配任意字符(除换行符);\1引用第 1 个捕获组的内容(即laoma);- 整体匹配 "
laoma laoniu+ 任意字符 + 再次出现laoma" 的部分,最终提取出符合该模式的字符串。
示例 2:匹配连续重复的单词
bash
[lth@controller ~ 19:28:29]$ echo 'Is is the cost of of gasoline going up up?' | \
> egrep -o '\b([a-z]+) \1\b'
# 过滤结果如下
of of
up up
- 解析:
\b是单词边界,确保匹配完整单词;([a-z]+)是第 1 个捕获组,匹配小写字母组成的单词;\1引用该单词,因此([a-z]+) \1表示 "一个单词 + 空格 + 相同单词";- 整体匹配连续重复的单词(如
of of、up up)。
示例 3:匹配重复 2 次及以上的单词
bash
[root@controller ~ 19:30:27]# echo 'Is is the cost of of of gasoline going up up?' | egrep -o '(\b[a-z]+\b\s+)\1{1,}'
# 过滤结果如下
of of of
- 解析:
(\b[a-z]+\b\s+)是第 1 个捕获组,匹配 "一个单词 + 空格"(\s+表示至少一个空格);\1{1,}表示引用该捕获组内容 1 次及以上,即 "(单词 + 空格) 重复 1 次以上";- 整体匹配同一单词连续出现 2 次及以上的情况(如
of of of是 "of + 空格" 重复 2 次)。
示例 4:匹配重复但中间空格不固定的单词
bash
[root@controller ~ 19:30:49]# echo 'Is is the cost of of of gasoline going up up?' | egrep -o '(\b[a-z]+\b\s+)\1{1,}'
# 过滤结果如下
of of
- 解析:
- 与示例 3 逻辑相同,但原字符串中
of of(两个空格)和of of(一个空格)分别被捕获; - 由于捕获组中
\s+允许任意多个空格,因此of of("of + 两个空格" 重复 1 次)符合模式,被提取为of of(输出时保留原始空格)。
- 与示例 3 逻辑相同,但原字符串中