了解POSIX扩展正则表达式
本文将简单介绍POSIX
扩展正则表达式。
什么是POSIX扩展正则表达式
POSIX
扩展正则表达式,也称ERE
(Extended Regular Expressions)是基于BRE
的扩展功能,目的是为正则表达式提供更加丰富的功能,和更加简洁的写法。
如何启用扩展正则表达式呢?
在grep
中,需要使用-E
选项来启用扩展功能,sed
也是同理,需要添加-E
来启用扩展,而awk
默认就支持该扩展功能。
新增、修改的点
取消了转义符
在ERE
中,BRE
需要转义的元字符,在ERE
中不需要再进行转义了,比如()
、{}
等。
新增的元字符
在ERE
中,新增了+
和?
的元字符,其含义是:
+
: 匹配前面的元素1次或者多次。?
: 匹配前面的元素0次或者1次。
操作
直接引用不需要转义
在ERE
中,可以直接引用{}
、()
中,而不需要进行转义,简化了写法,如:
wangli@debian:~$ echo "worrrrld" | grep -E 'r{1,3}'
worrrrld
wangli@debian:~$
wangli@debian:~$ echo "worrrld" | sed -E 's/(r{3})/-\1-/'
wo-rrr-ld
wangli@debian:~$
在BRE
中,需要将{}
和()
进行转义后,才能使用,写出来,可读性大大降低,在ERE
中,直接调用即可,可读性增强了。
同样的,如果只想表示{}
、()
本身的含义,需要用\
进行转义,如:
wangli@debian:~$ echo "2{35}" | grep -E '2{35}'
wangli@debian:~$
wangli@debian:~$ echo "2{35}" | grep -E '2\{35\}'
2{35}
wangli@debian:~$
新增的元字符
在ERE
中,新增了?
和+
2个元字符,前者表示匹配前面的字符0次或者1次,后者表示匹配前面的字符1次或多次,这其实也是简化了BRE
的写法,案例如下:
wangli@debian:~$ echo "1123" | grep -E '111?'
1123
wangli@debian:~$
wangli@debian:~$ echo "1123" | grep "111\{0,1\}"
1123
wangli@debian:~$
这里需要介绍下,为什么1123
可以使用111?
来获取到呢?首先?
的含义是表示匹配前面的字符0次或者1次,所以111?
会有2中情况:
11
,再匹配一个1
,结果是111
11
,不匹配后面的1
,结果是11
所以最后会被匹配到,同样的,使用BRE
来写的话,表达式为 111\{0,1\}
,然后功能完全一样,但是非常不直观。
再来看看+
呢。
wangli@debian:~$ echo "1111111123" | sed -E 's/(1+)/\1-/'
11111111-23
wangli@debian:~$
wangli@debian:~$ echo "1111111123" | sed 's/\(1\{1,\}\)/\1-/'
11111111-23
wangli@debian:~$
通过上面2个语句,可以发现虽然s/(1+)/\1-/
和s/\(1\{1,\}\)/\1-/
效果都是一样的,但是第一种要简单、直观很多,可读性要比第二种好。
一些关于正则表达式的例子
剔除多余的空格
有以下文本:
wangli@debian:~$ cat test.txt
grep prints
lines that contain a match for one or more patterns.
wangli@debian:~$
需要将多余的空格给剔除掉。
wangli@debian:~$ cat test.txt | sed -E -e 's/ +/ /g' -e 's/^ +//g'
grep prints
lines that contain a match for one or more patterns.
wangli@debian:~$
使用sed -e
可以执行多条命令,s/ +/ /g
表示将包含了多个连续空格都替换为1个空格,s/^ +//g
表示将以空格开头的连续空格都替换为空,即删除以空格开头的连续空格。
删除注释
定义注释的含义
# 这也是注释
# 这也是一种注释 #
# 这也是一种注释 # 这是正常的内容
有如下内容:
wangli@debian:~$ cat test.txt
# 这也是注释
# 这也是一种注释 #
# 这也是一种注释 # 这是正常的内容
a b e d # 含义是 a b c d
c d e f # 这是注释 # g h i j k
a # 注释 # b
# 这也是注释
# 这还是注释 # ccccc
ddd
aa
wangli@debian:~$
去除掉注释
wangli@debian:~$ cat test.txt | sed -E -e 's/#.*#//' -e 's/#.*//'
这是正常的内容
a b e d
c d e f g h i j k
a b
ccccc
ddd
aa
wangli@debian:~$
提取并且交换字符串中的两个数字
有以下文本:
wangli@debian:~$ cat test.txt
a 123 b c d e 456 f
wangli@debian:~$
需要将123
和456
顺序交换。
wangli@debian:~$ cat test.txt | sed -E -n 's/(.* )([0-9]{1,5})( .* )([0-9]{1,5})/\1\4\3\2/p'
a 456 b c d e 123 f
wangli@debian:~$
上面正则含义为:
(.* )
: 表示匹配以任何字符开头且任何长度的字符,并且以空格结束,并且设为分组1。([0-9]{1,5})
: 表示匹配1-5为数字,并且设置为分组2。( .* )
:表示匹配以空格开头和空格结尾的任何字符,并且设为分组3。([0-9]{1,5})
:表示匹配1-5为数字,并且设置为分组4。
有了如上的规则,就可以将a 123 b c d e 456 f
分为4组,分别为:
a
123
b c d e
456
此时,在引用分组的时候,只需要将4
和2
进行对调,则可以满足123
和456
交换。
获取机器的IP地址
wangli@debian:~$ ip a | sed -E -n 's/.* ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/[0-9]{1,3}.*/\1/p'
127.0.0.1
192.168.1.135
wangli@debian:~$
使用ip a
可以查询所有的IP信息
wangli@debian:~$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 08:00:27:7c:92:af brd ff:ff:ff:ff:ff:ff
inet 192.168.1.135/24 brd 192.168.1.255 scope global dynamic noprefixroute enp0s3
valid_lft 4631sec preferred_lft 4631sec
inet6 fe80::a00:27ff:fe7c:92af/64 scope link noprefixroute
valid_lft forever preferred_lft forever
wangli@debian:~$
使用的正则如下:
sed -E -n 's/.* ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/[0-9]{1,3}.*/\1/p'
使用sed -E
表示启用正则,而sed -n
表示只输出匹配的部分。
而正则表达式如下:
.* ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\/[0-9]{1,3}.*
意思为提取包含所有IP
地址和子网掩码的内容,并且只提取IP
部分,忽略子网掩码,其中IP
部分又规定了获取的是IPv4
格式。
所以,该正则表达式含义为:
.*
:匹配任何长度的字符,并且以空格结束。
([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})
: 匹配IPv4
地址,并且使用分组捕获。\/[0-9]{1,3}.*
:匹配斜杠/
和子网掩码部分。.*
:最后的匹配后面的所有字符。
提取URL中的协议、域名和路径
wangli@debian:~$ echo 'https://1.3.3.4/hello/world.txt' | sed -E -n "s|(.*)://([^/]+)/(.*)|s1:\1 s2:\2 s3:\3|p"
s1:https s2:1.3.3.4 s3:hello/world.txt
wangli@debian:~$
其中正则表达式为:
sed -E -n "s|(.*)://([^/]+)/(.*)|s1:\1 s2:\2 s3:\3|p"
其中[^/]+
的含义如下:
[]
表示一个字符集,[^/]
则表示除了/
以外的所有字符,后面的+
表示上一个字符至少出现1次,这里如果使用(.*)/
的话,会出现贪婪匹配。
总结
扩展正则表达式相对基础正则表达式而言,简化了写法,如{}
、()
不需要在额外转义了,还新增了+
和?
元字符。
有关正则表达式历史可以看下:正则表达式 - 维基百科,自由的百科全书 (wikipedia.org)。
了解POSIX扩展正则表达式
https://wangli2025.github.io/2024/11/08/Extended-Regular-Expressions.html
本站均为原创文章,采用 CC BY-NC-ND 4.0 协议。转载请注明出处,不得用于商业用途。