前面一篇文章,简单介绍了grep 查找命令的简单用法。链接:#Linux杂记# grep 查找命令常用选项大全(一)
本篇,注重讲述 grep 与 正则表达式的配合使用。在grep + RE 结合使用时,需要添加选项 “ -E ”。
先展示文件 grep.log 中的文本内容:
systemhoveveuvievevhveriloghovhsviesystemweeverilog
nldsveve 3234 s "test start"hlveuvvbe
systemmlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232
systemsystemlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232
vkvevhiu43876fiw28yjd24jbsdu9_+iuegr+wefyuwi
system7verilog
system7&verilog
we212system4verilog
##1f$$##www.baidu.com.www.qq.com%%
1. grep+元字符
.
:匹配任意单个字符,但不能匹配换行符\n
例子:
[my_basic_helloworld_1]grep -E "system.verilog" grep.log -i
system7verilog
we212system4verilog // system和verilog之间只允许有一个字符存在,匹配成功!
*
:匹配前面那个字符0或多次
例子:
[my_basic_helloworld_1]grep -E "system.*verilog" grep.log -i
systemhoveveuvievevhveriloghovhsviesystemweeverilog // 中间匹配任意多个字符
systemmlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232 // 中间匹配任意多个字符
systemsystemlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232 // 中间匹配任意多个字符
system7verilog // 中间匹配任意1个字符
system7&verilog // 中间匹配任意2个字符
we212system4verilog
?
:匹配前面那个字符0或一次
例子:
[ICer@IC_EDA /home/ICer/icer_pjs/my_basic_helloworld_1]grep -E "system.?verilog" grep.log -i
system7verilog // 中间匹配1个任意字符, 2个任意字符匹配失败
systemverilog // 中间匹配0个任意字符, 2个任意字符匹配失败
we212system4verilog // 中间匹配1个任意字符, 2个任意字符匹配失败
+
:匹配前面那个字符1次以上
例子:
[ICer@IC_EDA /home/ICer/icer_pjs/my_basic_helloworld_1]grep -E "system.+verilog" grep.log -i
systemhoveveuvievevhveriloghovhsviesystemweeverilog // 匹配前面那个字符1次以上,匹配成功
systemmlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232 // 匹配前面那个字符1次以上,匹配成功
systemsystemlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232 // 匹配前面那个字符1次以上,匹配成功
system7verilog // 匹配前面那个字符1次,匹配成功
system7&verilog // 匹配前面那个字符2次,匹配成功
we212system4verilog // 匹配前面那个字符1次,匹配成功
systemverilog // 匹配前面那个字符0次,匹配失败
{M,N}
:匹配前面那个字符至少M,最多N次
例子:
[my_basic_helloworld_1]grep -E "system.{5,20}verilog" grep.log -i
systemhoveveuvievevhveriloghovhsviesystemweeverilog
systemi am a student verilog // 匹配前面字符15次,匹配成功!5次以下和20次以上,均匹配失败!
systemi am a boy verilog // 匹配前面字符11次,匹配成功!5次以下和20次以上,均匹配失败!
{M,}
:匹配前面那个字符至少M次,最多无限制
例子:
略.....
{,N}
:匹配前面那个字符最多N次(最少当然是0次)。注意,perl正则不支持这种方式
例子:
略.....
{M}
:匹配前面那个字符正好M次
例子:
略.....
- 锚定:锚定的意思是匹配位置,而非匹配字符实体
^
:匹配行首位置,注意匹配的是位置,不是字符$
:匹配行尾位置,注意匹配的是位置,不是字符
例子:
[my_basic_helloworld_1]grep -E -e "^system" -e "verilog$" grep.log -i
systemhoveveuvievevhveriloghovhsviesystemweeverilog
systemmlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232
systemsystemlvevbvvvfdoivhdov2334bcbdv4f+verilog23k_13#nsiuvg2232
system7verilog
system7&verilog
systemverilog
systemi am a student verilog
systemi am a boy verilog
we212system4verilog
特殊且常用的的组合正则表达式:
^$
:它表示匹配空行.*
:匹配任意长度的任意字符,但不能匹配换行符。
2. grep+中括号[]
中括号[] : 表示的是匹配任意一个,一般它和字符集的排序规则有关,不同工具采取的排序规则可能也不一样。
[abcd...]
:匹配中括号内的任意一个字符
例子:
[my_basic_helloworld_1]grep -E "system[A-Z]verilog" grep.log -i
system7verilog
we212system4verilog
[my_basic_helloworld_1]grep -E "system[D]verilog" grep.log -i
systemDverilog
[^abcd...]
:拒绝匹配中括号内的任意字符[a-z]
:匹配字母a到z
[my_basic_helloworld_1]grep -E "system[a-z]verilog" grep.log -i
system7verilog
we212system4verilog
[A-Z]
:匹配字母A到Z
[my_basic_helloworld_1]grep -E "system[A-Z]verilog" grep.log -i
system7verilog
we212system4verilog
[0-9]
:匹配0-9,也就是匹配数字
例子:
[my_basic_helloworld_1]grep -E "system[0-9]verilog" grep.log -i
system7verilog
we212system4verilog
[my_basic_helloworld_1]grep -E "system[7]verilog" grep.log -i
system7verilog
关于字母的排序:
- perl中,A-Z排在a的前面,所以[A-z]表示所有大小写字母
- grep中,A-Z排在z的后面,所以[a-Z]表示所有大小写字母
- 还有些工具中,大小写的排序规则是aAbBcC...zZ,所以[a-C]表示aAbBcC共6个字母。
3. grep+ 字符类
特地专门命名的中括号序列;除了字符类,还有等价类、排序类,但基本用不上,只用字符类。
[:alpha:]
:匹配字母,等价于[a-zA-Z]
[:digit:]
:匹配数字,等价于[0-9]
[:xdigit:]
:匹配十六进制数,等价于[0-9a-fA-F]
[:upper:]
:匹配大写字母,等价于[A-Z]
[:lower:]
:匹配小写字母,等价于[a-z]
[:alnum:]
:匹配数字或字母,等价于[0-9a-zA-Z]
[:blank:]
:匹配空白,包括空格和制表符[:space:]
:匹配空格,包括空格、制表符、换行符、回车符等各种类型的空白[:punct:]
:匹配标点符号。包括:! ' " ` # $ % & ( ) * + , . - _ / : ; < = > ? @ [ \ ] ^ { | } ~
[:graph:]
:绘图类。包括:大小写字母、数字和标点符号。等价于[:alnum:]
+[:punct:]
[:print:]
:打印字符类。包括:大小写字母、数字、标点符号和空格。等价于[:alnum:]
+[:punct:]
+space[:cntrl:]
:控制字符类。在ASCII中,这些字符的八进制代码从000到037,还包括177(DEL)
需要注意的是,通常字符类在真正使用过程中,会再加上一个中括号,例如[[:alpha:]]
。之所以如此,是因为这些字符类只是一种命名好的字符集合。例如[:lower:]
对应的字符集合是a-z,而不是[a-z]
,所以要想让其表示这些命名字符类中的任一字符,需要再加上一层括号[[:lower:]]
,它才等价于[a-z]
。可能会更有助于理解使用字符类的时候为什么要加两个中括号的例子是[^[:lower:]]
,它表示不包含任何小写字母。
例子:
[my_basic_helloworld_1]grep -E "system[[:alpha:]]verilog" grep.log -i
systemDverilog
4. grep+ 反斜线序列
以下所说的单词,一般来说只包含数字、字母和下划线,即[_0-9a-zA-Z]
。以下几种反斜线序列,基本上所有工具都支持:
\b
:匹配单词边界处的空字符\B
:匹配非单词边界处的空字符\<
:匹配单词开头处的空字符\>
:匹配单词结尾处的空字符\w
:匹配单词构成部分,等价于[_[:alnum:]]
\W
:匹配非单词构成部分,等价于[^_[:alnum:]]
以下几种,有些工具不支持,但perl都支持:
\s
:匹配空白字符,等价于[[:space:]]
\S
:匹配非空白字符,等价于[^[:space:]]
\d
:匹配数字,等价于[0-9]
\D
:匹配非数字,等价于[^0-9]
由于元字符.
默认无法匹配换行符,所以需要匹配换行符的时候,可以使用特殊组合[\d\D]
来替换。换句话说,如果想匹配任意长度的任意字符,可以换成[\d\D]*
,当然,前提是必须支持\d
和\D
两个反斜线序列。
5. grep+ 分组捕获和反向引用
基础正则表达式中,使用括号可以对匹配内容进行分组并暂时保存,分组后会有分组编号,可以使用反斜线加编号\N
的方式反向引用这些分组。
分组编号的方式是从左向右计算括号数,无论如何嵌套,第一个左括号对应的分组一定是编号1,用\1
来引用,第二个左括号对应的分组一定是编号2,用\2
来引用,依此类推。
例如grep的分组捕获:匹配两个连续相同的字母。
echo "abcddefg" | grep -E "(.)\1"
可以认为分组就是变量赋值的过程。例如,上面示例的匹配过程如下:
1.匹配第一个字母a,放进分组,即赋值给变量(假设变量名为$1),即$1="a"
,再继续执行正则表达式匹配过程的反向引用,它引用的是$1,于是表示第一个字母a后面还要是字母a,于是匹配失败。
2.匹配第二个字母b,放进分组,即$1="b"
,再匹配后一个字母,于是匹配失败。
3.字母c同样如此。
4.匹配字母d,放进分组,即$1="d"
,再匹配后一个字母,发现匹配成功,于是$1被保存下来。
5.已经匹配成功,于是结束。
对于只使用基础正则的工具来说,一般都只能引用\1
到\9
共9个反向引用,最多自己额外提供一个所有表示匹配内容的反向引用(例如sed提供的&
)。对于超出10个的分组,使用基础正则的工具一般来说是无能为力的。
再者,基础正则仅仅只是将分组匹配到的内容捕获,在正则操作结束后就丢失。但对于一门完整编程语言来说,这远远不够,几乎所有编程语言(如perl/java/python等)都会将正则的分组匹配内容保存为变量,使得可以在正则结束之后再次引用甚至修改它们。例如上面例子中分组捕获的字母d,如果换成perl,即使在这个匹配过程结束后,还是可以去引用这段分组。
6. grep+ 二选一
pattern1 | pattern2
:匹配竖线左边或者匹配竖线右边,都算匹配成功。
二选一的结构几点需要说明:
- 因为竖线元字符的优先级很低,所以
ab|cd
匹配的是"ab"或"cd",而不是abd或acd。- 成功匹配了左边,就不会再去对右边进行匹配。
- 反向引用失败问题:竖线将两边的分组隔开,右边的永远无法反向引用左边的分组。
在二选一结构种,两个反向引用问题的典型例子:
例如a(.)|b\1
将无法匹配"ba",因为评估了左边就不会评估右边。
例如([ac])e\1|b([xyz])\2t
的左边能匹配aea或cec,但不能匹配cea或aec,右边能匹配bxxt或byyt或bzzt。但如果将\2
换成\1
,即([ac])e\1|b([xyz])\1t
,将无法匹配b[xyz]at或b[xyz]ct,因为第一个分组括号在左边,无法参与右边的正则评估。
例子1:
[my_basic_helloworld_1]grep -E "system[a-z]verilog|system[0-9]verilog" grep.log
system7verilog
we212system4verilog
例子2:
[my_basic_helloworld_1]grep -E "system[a-z]verilog|system[0-9]verilog" grep.log
systempverilog
system7verilog
we212system4verilog