UpDate 2018-10-22
Author unnam3d
Tip Please feel free to contact me via mail above for any confusion or suggestions
grep, egrep, fgrep - print lines matching a pattern
grep(Global Research)亦即根据某一个模式(过滤规则)去全局性的搜索文本,并将符合模式的文本行显示出来。grep其本身的意义是做部分匹配,也就是说,当你使用grep进行搜索的时候,只要某一行的内容里部分匹配,grep就会将结果显示出来。而这里的模式(Pattern)是指,文本字符和正则表达式的元字符组合而成的匹配条件。简而言之,grep就是使用基本正则表达式定义的模式来过滤文本的命令。
notice:grep 默认工作在贪婪模式下,也就是在匹配的过程中,会尽可能长的匹配,能匹配到哪就匹配到哪。
usage: grep [options] PATTERN [FILE...]
-
option
-i, --ignore-case:忽略模式和输入文件中的大小写
--colour, --color:将匹配到的内容彩色输出
-v:反向查找,显示没有被模式匹配到的行
-o:只显示被模式匹配到的字符串,每个字符串显示为一行
-E:使用扩展正则表达式
-A #:这其中的#表示一个数字,当使用grep匹配到字符串后,不仅显示匹配到的行,还显示该行后面#个行的内容,可以理解为after
-B #:同-A意义相同,不同的是,显示的是匹配到的行前面#个行的内容,可以理解为before
-C #:显示的是匹配到的行前后#个行的内容,可以理解为context
## option的例子
## *first* 表示 first是有颜色的
## grep -E = egrep 这里不做举例
## fgrep可以快速搜索,但不支持正则表达式,模式中的字符会被当做字符本身去匹配。
$ cat >> test.txt << EOF
> This is the first line
> This is the second line
> This is the third line
> EOF
$ grep -iv 'First' test.txt
This is the second line
This is the third line
$ grep --color 'first' test.txt
This is the *first* line
$ grep -io 'First' test.txt
first
$ grep -A1 'second' test.txt
This is the second line
This is the third line
$ grep -B1 'second' test.txt
This is the first line
This is the second line
$ grep -C1 'second' test.txt
This is the first line
This is the second line
This is the third line
正则表达式(REGgular EXPression, REGEXP)
正则表达式分为基本正则表达式(Basic REGEXP)与扩展正则表达式(Extended REGEXP)。
无论是哪一种,正则表达式都含义几个特性:
- 元字符
- 位置锚定
- 分组
元字符
正则表达式里都有一些元字符,这些元字符不表示其本身的意义,而是在正则表达式中有其特定的意义。我在bash特性简单梳理一文中提及过文件名通配(globbing)。
在文件名通配中,这些元字符的特定意义如下:
- '*' : 匹配任意长度的任意字符
- '?' : 匹配任意单个字符
- '[]' : 匹配指定范围内的任意单个字符
- '[^]' : 匹配指定范围外的任意单个字符
而在正则表达式中,元字符的特定意义为:
- '.': 表示任意单个字符
- '[]': 匹配指定范围内的任意单个字符
- '[^]': 匹配指定范围外的任意单个字符
- '*': 表示匹配其前面的字符任意次
- '.*': 表示任意长度的任意字符
- '?': 表示匹配其前面的字符1次或0次
- '\{m, n\}': 表示匹配其前面的字符至少m次,至多n次
除了这些特定的元字符的意义外,正如文件通配符中所描述的字符集合,正则表达式同样支持字符集合:
- [:space:] 表示空白字符
- [:punct:] 表示标点符号
- [:lower:] 表示小写字母
- [:upper:] 表示大写字母
- [:alpha:] 表示大小写字母
- [:digit:] 表示数字
- [:alnum:] 表示数字和大小写字母
# 示例解析
$ grep 'a.b' test.txt
它只能匹配a与b之间存在一个字符的字符串,而之间存在的字符串是什么是任意的。因此输出结果只有 aab, acb, adb
$ grep 'a*b' test.txt
它匹配的是以b结尾,b前面具有任意个a的字符串,任意个包括零个,因此它只匹配到了 b, ab, aab 而 acb adb amnbamnbamnb 也之所以显示出来,是因为grep的本身意义做的是部分匹配,只要改行有匹配到的内容就把该行显示出来。
$ grep 'a.*b' test.txt
它匹配的是以a开头,b结尾,中间可以存在任意个字符,且可以是任意字符。因此它就把a开头b结尾的所以字符都显示了出来,ab, aab, acb, adb, amnbamnbamnb
$ grep 'a\?' test.txt
它匹配包含一次a或者0次a的字符串,所以只要有a,就可以被检测出来,结果就如上了。
$ grep 'a\{1,\}b' test.txt
它匹配b前面最少有一次a的字符串,也就是ab, aab, aaab等等,所以结果如上。
$ grep 'a\{0,3\}' test.txt
它匹配包含最多三个a,所以结果如上。
位置锚定
位置锚定,就是在进行搜索的时候,所搜索的字符必须出现在特定的位置。
'^': 锚定行首,此字符后面的任意字符串内容必须出现在行首。
'$': 锚定行尾,此字符前面的任意字符串内容必须出现在行尾。
'^$': 锚定空白行,也就是搜索文件中的空白行。
'\<'或'\b': 锚定单词首部,此字符后面的任意字符串必须出现在单词首部。
-
'\>'或'\b': 锚定单词尾部,此字符后面的任意字符串必须出现在单词尾部。
notice: 这里单词的含义并不特指英文的单词,它只要以一个字符开始,以一个字符结束,中间只要没有出现特殊字符,它这个字符串整体就叫做单词,而这特殊字符包括:
. :
# 示例解析
$ grep '^r..t' test.txt
它将匹配到r..t的字符串,并且还是位于行首的行显示出来。
$ grep 'r..t$' test.txt
它将匹配到r..t的字符串,并且还是位于行尾的行显示出来。
$ grep '^$' test.txt
它将空白行显示出来
$ grep 'fork\>' test.txt
它将匹配到的字符fork,并且还是位于单词尾部的行显示了出来。
$ grep '\<ar' test.txt
它将匹配到的字符ar, 并且还是位于单词首部的行显示了出来。
$ grep '\<useful\>' test.txt
它将匹配到的字符useful, 并且是整个单词的行显示了出来。
分组
分组的意义,通俗的来讲,就是将一捆字符作为一个整体来看待,用\(\)
来表示。
例如:\(ab\)*
将ab作为一个整体,星号修饰的ab这一个整体。而ab*仅仅修饰b一个字符
$ grep '\(ab\)*' test.txt
上面这个命令就表示在文件test.txt
中匹配ab这一整体,它可以匹配到ab, abab, ababab这样。
后向引用
与分组搭配使用的还有后向引用。
\1: 引用第一个左括号以及与之对应的右括号所包括的所有内容
$ grep '\([0-9]\).*\1$' /etc/inittab
\2: 引用第二个左括号以及与之对应的右括号所包括的所有内容
\3: 引用第三个左括号以及与之对应的右括号所包括的所有内容
<练习>
以单个空格加单个数字结尾的行
$ grep '[[:space:]][[:digit:]]$' /etc/inittab
扩展正则表达式
扩展正则表达式与正则表达式在很多地方的意义都是相同的。例如:
-
字符匹配:
. [] [^]
次数匹配:
* ? {m,n}
位置锚定;
分组;
NOTICE:
- 次数匹配中的
?和{m,n}
不需要加反斜线 \ - 分组也不需要加反斜线,而且这里的分组才真正意义上实现了分组的意义。也支持
\1, \2, \3
的引用。
除了与正则表达式相同意义的地方,扩展表达式也有其独特的地方:
次数匹配中
+
加号代表基本正则表达式中的\{1,\}
,所以加号代表匹配其前面的字符至少一次-
支持逻辑或:a|b = a 或 b
C|cat: C或cat
$ grep --color -E 'C|cat' test.txt
(C|c)at: Cat或cat
$ grep --color -E '(C|c)at' test6.txt
-
grep -E = egrep
egrep --color '\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>' /boot/grub/grub.conf
练习
- 找出ifconfig命令中0-255之间的数字
- 找出ifconfig命令中形如x.x.x.x格式的数字格式
- 找出ifconfig命令中的ip地址
答案
ifconfig | egrep --color '\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>'
ifconfig | egrep --color '(\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.){3}\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>'
ifconfig | egrep --color '(\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>\.){3}\1'
ifconfig | egrep --color '\<[1-9]|[1-9][0-9]|1[0-9]{2}|2[01][0-9]|22[0-3]\>(\.\<([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])\>){2}\.\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])\>'