写在前面:
一直以来 对于正则表达式的使用都没有进行一个系统性的梳理学习,导致在工作中进行脚本编写时,总是会出现一些不符合自己认知的错误,最近抽空将其进行了系统性的学习与梳理
所谓正则表达式 是对文本中的字符串进行处理的一种工具,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符),不表示字符字面意思,而表示控制或通配的功能
程序支持:grep,sed,awk,vim,less,nginx,varnish等
分两类:
基本正则表达式:BRE
扩展正则表达式:ERE
正则表达式元字符的分类
字符匹配、匹配次数、位置锚定、分组 (有特定功能的字符)具体含义会在下文中进行详细的说明
本文中对正则表达式的使用,是通过grep 命令进行示例的,如果对grep 不够清楚,可以去看我的文章Linux 中的正则表达式应用工具(grep,sed,awk)
废话不多说,接下来就是干货
字符匹配,正则表达式中常用来代替字符的一些匹配模式
正则字符 | |
---|---|
. | 匹配任意单个字符 |
[] | 匹配指定范围内的任意字符 |
[^] | 匹配指定范围外的任意字符 |
[:alnum:] | 字母和数字 |
[:alpha:] | 代表任何英文大小写字符,亦即A-Z,a-z |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:black:] | 空白字符(空格和制表符) |
[:space:] | 水平和垂直的空白字符(比[:blank:]包含的范围广) |
[:cntrl:] | 不可打印的控制字符(退格、删除、警铃…) |
[:digit:] | 十进制数字 |
[:xdigit:] | 十六进制数字 |
[:graph:] | 可打印的非空白字符 |
[:print:] | 可打印字符 |
[:pumct:] | 标点符号 |
以上这些字符需要记住,笔者建议在通过多次练习进行记忆,不建议不明缘由的死记硬背,毕竟实践出真知
对上述正则符号的使用进行个别示例
. 匹配任意单个字符
[] 中括号中的的任意一个字符进行匹配
上图grep 过滤条件 a[bcdef]c 指的是 标准输出中需要有符合 abc or acc or adc or arc or afc 排列的字符
[^] 匹配非中括号内指定的字符
如上图所示,结合上个示例,只要不是中括号中内容,都会被匹配出来
匹配次数:用来指定所给出的匹配字符,出现的次数,满足限定才会被匹配出来
字符 | 含义 | 实例 |
---|---|---|
* | * 前的字符出现0次 ~n >=0 | * 号前的字符,未匹配到或者匹配到任意次,即n*m表达的是 m, nm, nnm, nnnnnm |
.* | 任意长度的任意字符串 | 比如 p.*q 表达的是 pq, psq, pasgeq |
\? | 匹配前面字符0次或1次前面的字符出现0次或1次 | 既 n?m 表达的是 nm m 而不是 nnm |
\ + | 匹配其前面的字符串直至少一次 | 例如:n+m 表达的是 nm |
\ {n\ } | 匹配前面的字符n次 | 例如 p{2}\q 表达的是 ppq |
\ {m,n\ } | 匹配前面的字符m 到 n 次 | 例如 p\ {2,5\ }q 表达的是ppq, pppq, ppppq, pppppq |
\ {,n\ } | 匹配前面的字符至多n 次 | 例如 p{,3}\q 表达是 q, pq, ppq, pppq |
\ {n,\ } | 匹配前面的字符直少n次 | 例如 p{3,}\q 表达的是 pppq, ppppq, ppp…q |
示例如下:
字符匹配[] 和次数匹配 ? 结合使用
[root@7 grep]# echo abccdd |grep "a[a-z]\?c"
# "a[a-z]\?c" 表示匹配 ac aac abc 等等 azc 在内的所有字符
# [a-z] 表示匹配所有的小写字母
# [a-z]\? 表示 \? 前面的字符出现 0 次或 1 次都符合条件
\ {m,n\ } 次数匹配
[root@7 grep]# grep "ro\{,2\}t" /etc/passwd
# ro\{,2\}t 表示 o 字符至多出现 2 次
小练习:使用正则表达式的字符匹配和位置匹配,进行如下需求匹配
笔者给出的匹配结果如下所示,建议读者先自行尝试 ^ v ^
[root@7 grep]# df |grep /dev/sd | grep -o '[0-9]\{,3\}%' |sort -nr |head -n1
# grep /dev/sd 匹配出所需要的磁盘
# -o 表示只显示匹配出的字符
# [0-9]\{,3\}% 磁盘利用率在 0-100之间,所以需要限定数字0-9出现0-3次,再加上 % 号的限定 就可取出磁盘利用率
# sort -nr 按数字进行反向排序
# head -n1 取第一行内容
位置锚定:确定匹配字符出现的位置
字符 | 含义 |
---|---|
^ | 行首锚定,用于模式的最左侧 |
$ | 行尾锚定,用于模式的最左右侧 |
\ 以对应匹配为词首的单词 |
|
pattern\ > | 以对应匹配为词尾的单词 |
\ b | 表示单词的边界,既可以表示单词的词首,也可以表示单词的词尾 |
[root@7 grep]# grep -v '^$' f1
# ^$ 表示以空字符开头结尾的行
匹配结果如下:还有几行空白被匹配出来
这是因为文件空行中存在 空格 和 制表符(tab)所以不是真正意义上的空行
想要过滤正真意义上的空行需要进行如下匹配
[root@7 grep]# grep -v '^[[:space:]]*$' f1
# ^[[:space:]]*$ 表示为任何空字符的行
对规定的词首进行匹配
[root@7 shell_test]# grep '\
[root@7 shell_test]# grep 'root\>' /etc/passwd
# root\> :匹配以root结尾的字符
[root@7 shell_test]# grep '\broot' /etc/passwd
[root@7 shell_test]# grep 'root\b' /etc/passwd
进行完整字符的匹配,等同于grep -w
[root@7 shell_test]# grep '\' /etc/passwd
[root@7 shell_test]# grep '\broot\b' /etc/passwd
[root@7 shell_test]# grep -w 'root' /etc/passwd
分组:通过\ (\ ) 将一个或多个字符捆绑在一起,当作一个整体进行处理
\(\) | 将一个或多个字符捆绑在一起,当作整一个整体进行处理, | 如:\ (root\ )\ + 匹配 root 字符至少一次 如 root,rootroot,rootrootroot |
分组括号中的模式匹配到的内容,会被正则表达式引擎纪录于内部的变量中,这些变量的命名方式为:\1,\2,\3,…
后向引用:\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符结果,而不是相应的模式
eg | \ (string1 \ +\ (string2\ ) * \ ) |
\1 | string1 \ +\ (string2\ )* |
\2 | string2 |
或者:\ |匹配中的或条件
eg: | |
a\| b | a或b |
C\|cat | C或cat |
\ (C\ |c \ )at | Cat 或cat |
示例:
[root@7 shell_test]# echo rootxxroot |grep '\(r..t\).*\1'
# 上面的 \1 指代的是 \(r..t\) 匹配到的字符 root 而不是 r..t 这个模式类型
[root@7 shell_test]# echo rootxxrxxt |grep '\(r..t\).*\1'
# 这里就无法匹配到
[root@7 shell_test]# grep '^\(.\+\):.*\1$' /etc/passwd
# ^\(.\+\):.*\1$ 以任意字符开头并匹配到:,中间也是任意字符 最后以 ^\(.\+\) 匹配到的内容结尾
# ^\(.\+\): 以任意字符开
# \1 以上式匹配到的内容结尾
[root@7 shell_test]# grep '^\(.*\):.*\1$' /etc/passwd
# 此种方式也可
或者 \| 的使用
匹配/etc/passwd 中的包含bash 或者 root 的行
[root@7 shell_test]# grep 'root\|bash' /etc/passwd
扩展正则表达式可以认为是对基础正则的简化,直观上的表现 :
如进行分组时 基础正则使用 \(\) 扩展正则,则直接使用()
grep sed 等文本处理工具,配上指定的选项,可进行扩展正则的使用
grep -E 或 egrep
sed -r
字符匹配 | 和基本正则相同 |
---|---|
. | 匹配任意单个字符 |
[] | 匹配指定范围内的任意字符 |
[^] | 匹配指定范围外的任意字符 |
[:alnum:] | 字母和数字 |
[:alpha:] | 代表任何英文大小写字符,亦即A-Z,a-z |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:black:] | 空白字符(空格和制表符) |
[:space:] | 水平和垂直的空白字符(比[:blank:]包含的范围广) |
[:cntrl:] | 不可打印的控制字符(退格、删除、警铃…) |
[:digit:] | 十进制数字 |
[:xdigit:] | 十六进制数字 |
[:graph:] | 可打印的非空白字符 |
[:print:] | 可打印字符 |
[:pumct:] | 标点符号 |
次数匹配 | 相比基本正则简单 |
---|---|
* | 匹配前面字符任意次 |
? | 0次或1次 |
+ | 1次或多次 |
{m} | 匹配m次 |
{m,n} | 至少m,之多n次 |
位置锚定 | |
---|---|
^ | 行首 |
$ | 行尾 |
\<,\b | 词首 |
\>,\b | 词尾 |
分组 | 相比基本正则简单 |
---|---|
() | |
后向引用 | \1,\2 |
或者 | 相比基本正则简单 |
---|---|
a|b | a或b |
C|cat | C或cat |
(C |c)at | Cat或cat |
以上文中:“匹配出/etc/passwd 文件中 用户名和 使用的shell 相同的行” 为示例
分组
[root@7 shell_test]# egrep '^(.*):.*\1$' /etc/passwd
# egrep : grep 使用扩展正则 等同于 grep -E
# ^(.*):.*\1$ : 以任意字符开头并匹配到:,中间也是任意字符 最后以 ^\(.\+\) 匹配到的内容结尾
[root@7 shell_test]# egrep 'root|bash' /etc/passwd
小练习:
找出/etc/passwd 中的uid /gid 为两位或三位数字 的用户
[root@7 shell_test]# egrep '\b[0-9]{2,3}\b' /etc/passwd
取出三个用户 root 、bleach、test 用户的UID 和默认shell (没有u对应的用户直接使用useradd 进行创建)
[root@7 shell_test]# egrep '^\b(root|bleach|test)\b' /etc/passwd |cut -d: -f1,3,7
取出 /etc/sysconfig/network-scripts/ifcfg-ens33 文件路径中的文件名 或者 目录名称
[root@7 shell_test]# echo /etc/sysconfig/network-scripts/ifcfg-ens33 |egrep '[^/]*/?$'
[root@7 shell_test]# echo /etc/sysconfig/network-scripts/ifcfg-ens33 |egrep -o '.*/'
[root@7 shell_test]# ifconfig ens33 |egrep -o '([0-9]{,3}\.){3}[0-9]{,3}' |head -n1