Linux 正则表达式

低功耗蓝牙项目,需要一块懂省电的板

思澈 SF32LB52 芯片,BLE 协议栈深度优化,上手即开发

Linux 正则表达式

  • 正则表达式作为一个 pattern,将 pattern 与要搜索的字符串进行匹配,以便查找一个或多个字符串。
  • 正则表达式,自成体系,由普通字符(例如字符 a 到 z)和元字符组成的文字模式。
    • 普通字符:没有显式指定为元字符的所有可打印和不可打印字符字符,包括所有大写和小写字母、所有数字、所有标点符号和其他一些符号。
    • 元字符:出了普通字符之外的字符。
  • 正则表达式,工具(vim、grep、less等)和程序语言(Perl、Python、C等)都使用正则表达式。

正则表达式分类:

  • 普通正则表达式
  • 扩展正则表示,支持更多的元字符

环境准备

[yy@controller zz 15:21:22]$ vim words
cat
category
acat
concatenate
dog

字符集

[…]

匹配 [...] 中的任意一个字符。

[yy@controller zz 15:22:28]$ echo cbt >> words
[yy@controller zz 15:22:49]$ echo c1t >> words
[yy@controller zz 15:22:58]$ cat words | grep 'c[ab]t' 
cat
category
acat
concatenate
cbt

[a-z] [A-Z] [0-9]
  • [a-z],匹配所有小写字母。
  • [A-Z],匹配所有大写字母。
  • [0-9],匹配所有数字。
[yy@controller zz 15:23:23]$ cat words | grep 'c[a-z]t'
cat
category
acat
concatenate
cbt

[yy@controller zz 15:24:16]$ echo cCt >> words
[yy@controller zz 15:24:23]$ cat words | grep 'c[A-Z]t'
cCt
[yy@controller zz 15:24:35]$ cat words | grep 'c[0-9]t'
c1t
[yy@controller zz 15:24:48]$ cat words | grep 'c[a-z0-9]t'
cat
category
acat
concatenate
cbt
c1t
[yy@controller zz 15:25:02]$ cat words | grep 'c[A-Za-z0-9]t'
cat
category
acat
concatenate
cbt
c1t
cCt
[yy@controller zz 15:25:23]$ echo c-t >>words

# 要想匹配-符号,将改符号写在第一个位置
[yy@controller zz 15:25:56]$ cat words | grep 'c[-a-zA-Z0-9]t'
cat
category
acat
concatenate
cbt
c1t
cCt
c-t

[^…]

匹配除了 [...] 中字符的所有字符。

[yy@controller zz 15:26:13]$ cat words | grep 'c[^ab]t'
c1t
cCt
c-t

# ^放中间会被当做普通字符
[yy@controller zz 15:27:20]$ cat words | grep 'c[a^b]t'
cat
category
acat
concatenate
cbt

.

匹配除换行符(\n\r)之外的任何单个字符,相等于\[^\n\r]

[yy@controller zz 15:27:28]$ cat words | grep 'c.t'
cat
category
acat
concatenate
cbt
c1t
cCt
c-t

\

将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。

例如, ‘n’ 匹配字符 ‘n’。\n 匹配换行符。序列 \\ 匹配 \,而 \( 则匹配 (

[yy@controller zz 15:28:25]$ echo c.t >> words
[yy@controller zz 15:28:39]$ cat words | grep 'c\.t'
c.t


[yy@controller zz 15:28:41]$ cat words | grep 'c\at'
cat
category
acat
concatenate

|

| 符号是扩展表达式中元字符,指明两项之间的一个选择。要匹配 |,请使用 \|

# 使用egrep或者grep -E 匹配
[yy@controller zz 15:29:37]$ cat words | egrep 'cat|dog'
cat
category
acat
concatenate
dog


[yy@controller zz 15:29:47]$ 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

定位符

^

匹配行首位置。

[yy@controller zz 17:19:10]$ cat words | grep '^cat'
cat
category

#查看/etc/profile文件中的有效行
[yy@controller ~ 15:41:50]$ cat /etc/profile | egrep -v '^#|^$'
#-v 取反,不显示匹配内容 

$

匹配行末位置。

[yy@controller zz 19:25:52]$ cat words | grep 'cat$'
cat
acat
[yy@controller zz 19:26:09]$ cat words | grep '^cat$'
cat
\b

匹配一个单词边界。

[yy@controller zz 19:26:15]$ echo hello cat >> words
[yy@controller zz 19:30:31]$ cat words | grep '\bcat'
cat
category
hello cat
[yy@controller zz 19:30:54]$ cat words | grep 'cat\b'
cat
acat
hello cat

[yy@controller zz 19:31:14]$ cat words | grep '\bcat\b'
cat
hello cat
\B

非单词边界匹配。

[yy@controller zz 19:31:28]$ cat words | grep '\Bcat'
acat
concatenate
\< 和 \>
  • \< ,匹配一个单词左边界。
  • \>,匹配一个单词右边界。
[yy@controller zz 19:32:21]$ cat words | grep '\<cat'
cat
category
hello cat
[yy@controller zz 19:33:53]$ cat words | grep 'cat\>'
cat
acat
hello cat

限定次数

*

匹配前面的子表达式任意次数

[yy@controller zz 19:34:08]$ echo dg >> words
[yy@controller zz 19:35:27]$ echo doog >> words
[yy@controller zz 19:35:32]$ cat words | grep 'do*g'
dog
dg
doog

* 表示匹配前面的字符零次或多次

在模式 do*g 中:

  • dg 是固定字符
  • o* 表示匹配字母 o 零次、一次或多次

所以:

  • dg:匹配(o 出现了 0 次)
  • dog:匹配(o 出现了 1 次)
  • doog:匹配(o 出现了 2 次)
+

+ 是扩展表达式元字符,匹配前面的子表达式一次以上次数

[yy@controller zz 19:36:45]$ cat words | egrep 'do+g'
dog
doog

grepegrep 都是用于文本搜索的工具,它们的主要区别在于对正则表达式的支持程度,选择使用哪一个取决于你的需求:

1. 功能差异

  • grep:默认支持基础正则表达式(BRE),部分元字符(如 +?| 等)需要转义(加 \)才能生效。
  • egrep:等价于 grep -E,支持扩展正则表达式(ERE),上述元字符可以直接使用,无需转义。

2. 使用场景

  • grep 的情况
    • 只需使用简单的匹配模式(如固定字符串、基础元字符 *^$ 等)。
    • 脚本兼容性要求较高(某些古老系统中 egrep 可能行为不同)。
  • egrep(或 grep -E)的情况
    • 需要使用复杂的正则表达式,如:
      • 多选结构(a|b 表示匹配 a 或 b)
      • 量词 +(一次或多次)、?(零次或一次)
      • 分组 (...)
    • 希望表达式更简洁(无需大量转义符)。

示例对比

  • 匹配 catdog
    • egrep 'cat|dog' file(直接使用 |
    • grep 'cat\|dog' file(必须转义 |
  • 匹配至少一个 o(如 dogdoog):
    • egrep 'do+g' file(直接使用 +
    • grep 'do\+g' file(必须转义 +
?

? 是扩展表达式元字符,匹配前面的子表达式一次以下次数

[yy@controller zz 19:37:05]$ cat words | egrep 'do?g'
dog
dg

在模式 do?g 中:

  • dg 是固定字符
  • o? 表示匹配字母 o 零次或一次

所以:

  • dg:匹配(o 出现了 0 次)
  • dog:匹配(o 出现了 1 次)
  • doogo 出现 2 次)则不会被匹配,因为 ? 不允许出现多次
{n}

{} 是扩展表达式元字符,用于匹配特定次数。例如:{n},配置n次。

[yy@controller zz 19:38:47]$ cat words | egrep 'do{2}g'
doog
{m,n}

{m,n},是扩展表达式元字符,用于匹配次数介于m-n之间。

[yy@controller zz 19:39:36]$ echo dooog >> words
[yy@controller zz 19:40:05]$ echo doooog >> words
[yy@controller zz 19:40:13]$ cat words | egrep 'do{2,3}g'
doog
dooog
{m,}

{m,},是扩展表达式元字符,匹配前面的子表达式m次以上次数

[yy@controller zz 19:40:19]$ cat words | egrep 'do{2,}g'
doog
dooog
doooog
{,n}

{,n},是扩展表达式元字符,匹配前面的子表达式n次以下次数

[yy@controller zz 19:40:39]$ cat words | egrep 'do{,3}g'
dog
dg
doog
dooog
()

标记一个子表达式。

[yy@controller zz 19:40:53]$ echo dogdog >> words
[yy@controller zz 19:41:22]$ echo dogdogdog >> words
[yy@controller zz 19:41:27]$ echo dogdogdogdog >> words
[yy@controller zz 19:41:32]$ cat words | egrep '(dog){2,3}'
dogdog
dogdogdog
dogdogdogdog
[yy@controller zz 19:42:04]$ cat words | egrep '(dog){2,}'

dogdog
dogdogdog
dogdogdogdog

egrep '(dog){2,3}' 中:

  • (dog) 是一个分组,表示整体匹配 “dog” 这个字符串
  • {2,3} 是量词范围,表示前面的分组需要出现至少 2 次,最多 3 次

所以匹配结果包括:

  • dogdog(出现 2 次)
  • dogdogdog(出现 3 次)

egrep '(dog){2,}' 中:

  • {2,} 表示前面的分组需要出现至少 2 次,次数上限不限制

因此除了上述两个结果外,还匹配了 dogdogdogdog(出现 4 次)。

这种语法在需要精确控制重复次数时非常有用,比如验证密码长度、匹配特定格式的重复模式等。在扩展正则表达式(egrepgrep -E)中可以直接使用 {n,m} 形式,而在基础正则表达式(普通 grep)中需要转义为 \{n,m\} 才能生效。

**思考:**如何过滤出以下文件中所有有效IPv4地址?

0.0.0.0
1.1.1.1
11.11.11.111
111.111.111.111
999.9.9.9
01.1.1.1
10.0.0.0
0.1.1.1
266.1.1.1
248.1.1.1
256.1.1.1

参考答案

\b(([1-9][0-9]?)|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))(\.(([0-9])|([1-9][0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))){3}\b

'\b([1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){2}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\b'
拆解说明:
  1. \b:单词边界,确保匹配的是完整的 IP 地址,避免与其他字符串粘连(如192.168.1.1abc不会被误匹配)。
  2. 第一个数字段(octet)([1-9][0-9]?)|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5])
    • [1-9][0-9]?:匹配 1-99(不允许前导零,如01无效,但1有效)。
    • 1[0-9]{2}:匹配 100-199(如100199)。
    • 2[0-4][0-9]:匹配 200-249(如200249)。
    • 25[0-5]:匹配 250-255(如250255)。
    • 整体确保第一个数字段是 1-255 且无前置零(特殊情况:0需单独看后续规则)。
  3. 后续三个数字段(\.(([0-9])|([1-9][0-9])|(1[0-9]{2})|(2[0-4][0-9])|(25[0-5]))){3}
    • \.:匹配点号(.),用于分隔数字段。
    • 内部([0-9])|...:允许 0-255(包含单个0,如0有效,但01无效)。
    • {3}:表示重复 3 次,即总共匹配后 3 个数字段(加上第一个,共 4 个)。
  4. \b:结尾的单词边界,与开头呼应。
反向引用

对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。

每个缓冲区都可以使用 \N 访问,其中 N 为一个标识特定缓冲区的一位或两位十进制数。

\N 这用引用方式称之为反向引用。

[laoma@shell ~]$ echo 'laoma laoniu laohu laoma laoniu laohu' | \
> egrep -o '(laoma) (laoniu).*\1'

# 过滤结果如下
laoma laoniu laohu laoma

[laoma@shell ~]$ echo 'Is is the cost of of gasoline going up up?' | \
> egrep -o '\b([a-z]+) \1\b' 
# 过滤结果如下
of of
up up

[root@server ~]#  echo 'Is is the cost of of of gasoline going up up?' | egrep -o '(\b[a-z]+\b\s+)\1{1,}'
# 过滤结果如下
of of of

[root@server ~]# echo 'Is is the cost of  of of gasoline going up up?' | egrep -o '(\b[a-z]+\b\s+)\1{1,}'
# 过滤结果如下
of of

低功耗蓝牙项目,需要一块懂省电的板

思澈 SF32LB52 芯片,BLE 协议栈深度优化,上手即开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值