基本匹配
-
\<表示锚定词首 -
\>表示锚定词尾 -
\b既能锚定词首,也能锚定词尾 \B与\b相反,\b使用来匹配「单词边界」的,但是\B刚好相反比如有 morning 和 goodmorning 两个字符串,\bmorning 可以匹配到 morning,无法匹配到 goodmorning, 而 \Bmorning 匹配到的是 goodmorning,而不会匹配到 morning。
-
^ 表示锚定行首
- $ 表示锚定行尾
次数匹配
根据指定字符的连续出现次数进行匹配
-
{n}表示指定的字符连续出现 n 次 -
{m,n}字符连续出现的次数介于 m 和 n 之间 -
{,n}字符连续出现的次数不高于 n,下限不做限制 -
{m,}字符连续出现的次数不低于 m,上线不做限制 -
*匹配任意长度的字符,包括长度为 0
如
abc*能匹配 ab, abc, abcc, abccc 等。
.匹配任意单个字符,换行符除外
如 ‘.’ 能匹配 a, b, c, d 等
-
.*则用来匹配任意长度的任意字符 -
\?匹配规则为:字符出现 0 次或者 1 次 -
\+匹配规则为:字符至少出现 1 次 -
[]匹配范围内的任意单个字符 -
[^]匹配范围外的单个字符
字符类型的匹配
-
[[:alpha:]]匹配任意单个字母,不区分大小写,与[a-zA-Z]等效。 -
[[:digit:]]匹配任意单个 0-9 的单个数字,与[0-9]等效。 -
[[:lower:]]匹配任意单个小写字母,与[a-z]等效。 -
[[:upper:]]匹配任意单个大写字母,与[A-Z]等效。 -
[[:alnum:]]匹配任意单个字母或者数字,与[a-zA-Z0-9]等效。 -
[[:space:]]匹配任意单个空白字符,包括「空格」「Tab制表符」等。 -
[[:punct:]]匹配任意单个标点符号。
分组与后向引用
啥是分组
举个例子。
有个文档 list_1,我们查看一下内容。
root@Simona:~# cat -n list_1
1 goodgoodverygood
2 goodddgoodgood
3 123412341234
比如想找到连续出现两次的 good 字符串,该如何操作呢?使用 \{n\} 可以进行次数匹配,但是它表示该匹配符前面的单个字符重复出现 n 次,因此使用 grep 'good\{2\}' list_1 无法实现我们的目标。
root@Simona:~# grep -n 'good\{2\}' list_1
2:goodddgoodgood
该命令匹配的是第 2 行的 goodddgoodgood
上面对内容的匹配,都是针对单个字符的。如果要匹配某个单词重复若干次,这个时候使用分组就对了。
root@Simona:~# grep -n '\(good\)\{2\}' list_1
1:goodgoodverygood
2:goodddgoodgood
使用上面的匹配模式,匹配结果是 goodgoodverygood 以及 goodddgoodgood。
分组,就是将若干连续的字符视为一个整体作为匹配的对象。上面例子中,就是将 good 四个字符分成一组进行匹配的。
\(\) 就是分组匹配符,\(good\) 就是将 good 作为一组去匹配。
啥是后向引用
所谓后向引用,就是利用前面分组所匹配的对象,对后面的内容进行匹配。
举个例子。查看一下文件 list_2 的内容
root@Simona:~# cat -n list_2
1 god & gun
2 god & god
使用下面的匹配规则
root@Simona:~# grep -n '.\{3\} & .\{3\}' list_2
1:god & gun
2:god & god
可以看到,该模式会将两行都匹配出来。如果我们只想匹配第 2 行呢,就是说,对于该文本的每一行,要求 & 符号前后的字符串一致。这个时候可以使用后向应用进行匹配。看一看下面的例子。
root@Simona:~# grep -n '\(.\{3\}\) & \1' list_2
2:god & god
对于上面的匹配模式,\(.\{3\}\) 匹配了三个字符,并分组将其作为一个整体。接下来的 \1 就是后向应用的标志,表示引用前面第一个分组表达式匹配的结果。
\1 表示第 1 个分组的匹配结果,\2 表示第 2 个分组的匹配结果,\3 等以此类推。
对于多个分组的匹配模式,按照分组开始的位置进行排序。如 \(first\(second\)ok\),first 前面的对应的 ( 定义了第一个分组,second 前面的 ( 定义了第二个分组。
转义符
使用正则表达式对文本进行匹配的时候,用 . 表示来匹配一个字符(换行符除外)。那么,如果我们想匹配的是 . 这个字符本身,该如何做呢?同理,想匹配 *, ? 这种符号,又该怎么处理呢?这就涉及到转义符了。
\ 就是转义符。
如果想匹配 .,使用 \. 进行转义;同理,想匹配 *,使用 \* 进行转义。
看看例子,先查看一下文本的内容。
root@Simona:~# cat -n list_3
1 a..
2 a**
3 a*#
4 a(*
我们想使用 a.. 来匹配第一行,实际情况是,. 可以匹配任意一个单个字符,因此,被匹配到的不仅仅是 「a..」,「a**」 和 「a*#」 等也被匹配到了。
root@Simona:~# grep -n 'a..' list_3
1:a..
2:a**
3:a*#
4:a(*
接下来,我们使用转义符进行转义。
root@Simona:~# grep -n 'a\.\.' list_3
1:a..
可以发现,在使用了 \ 进行转义之后,只有第 1 行匹配成功。同理,如果想匹配 * 本身,使用 \* 进行转义匹配。对于 ( 这种标点,直接使用 ( 进行匹配就可以了。
对于上面的文本,我们想匹配第 4 行的 「a(*」。
root@Simona:~# grep -n 'a(\*' list_3
4:a(*
在 shell 中通过 grep 工具使用正则
环境配置
+ Ubuntu 16.04.2
+ /bin/bash
使用 grep 进行正则匹配的时候,正则表达式可以用单引号
''包裹起来,不要使用双引号"",否则可能有惊喜。
使用示例
- 匹配一个 uuid 字符串
echo 9ea18301-3b7e-8e72-2566-7856cb543762 | grep '^[[:alnum:]]\{8\}-[[:alnum:]]\{4\}-[[:alnum:]]\{4\}-[[:alnum:]]\{4\}-[[:alnum:]]\{12\}$'
字符匹配规则的简写
-
\d表示任意单个0到9的数字 -
\D表示任意单个非数字字符 -
\t表示匹配单个横向制表符(相当于一个tab键) -
\s表示匹配单个空白字符,包括「空格」,「tab制表符」等 -
\S表示匹配单个非空白字符
扩展正则表达式
在 Linux 中,grep 工具默认使用「基本正则表达式」去匹配字符串,如果要使用「扩展正则表达式」,则需要加上 -E 选项。
在使用上,基本的匹配规则是通用的,相比于「基本正则表达式」,「扩展正则表达式」更加简洁。举两个例子, \{\} 与 {} 对应,\(\) 与 () 对应,可以看到,不用再写转义符 \ 了,表达式更简洁,语义化也更好。
「扩展正则表达式」中,有一个「基本正则表达式」没有的匹配符,就是 | 符号,用来表示「或」的关系。看例子:
root@Simona:~# cat -n list_4
1 www.simona.xyz
2 www.baidu.com
3 www.coding.net
root@Simona:~# grep -nE '(net|com)$' list_4
2:www.baidu.com
3:www.coding.net