大家好,欢迎你们来到我的博客,作为一个博客新手,这是我第一次发帖子,希望接下来的时间我们能够在linux的学习中互帮互助,共同进步!
好了,废话不多说,回归正题,今天我将要介绍的是非常强大的文本搜索工具--grep。
grep的全称为:Globel Search Regular Expression and Printing out the line(全局搜索正则表达式并把行打印出来)。它最重要的功能根据用户指定的文本模式(搜索条件)对目标文件进行逐行搜索,然后将符合要求的字符串打印出来,但必须声明的是,grep在数据选取的时候是以行为单位的。
grep家族中共有grep,egrep,fgrep三位成员,而我们今天主要对其中的grep以及egrep命令进行讲解,因为它们是我们在以后的学习中更加常用的两个命令。
一、首先我们先对grep进行介绍:
1、grep的语法格式
grep [option]... 'PATTERN' FILE...
命令 选项 模式 文件
需要注意的是:grep在引用变量的时候必须加双引号(这个的话在我们以后的shell脚本的学习会用的比较多)
2、基本正则表达式的元字符
想要正确的匹配好模式的话我们不得不先对基本正则表达式的元字符进行介绍,这也是我们学习grep中pattern的关键所在。
下面是基本正则表达式的元字符:
1)字符匹配:
. : 表示匹配任意单个字符
[]: 表示匹配指定范围内的任意单个字符
[0-9],[[:digit:]] :表示0到9的任意数字
[a-z], [[:lower:]] :表示任意单个小写字母
[A-Z], [[:upper:]] :表示人以单个大写字母
[[:space:]] :表示一个空格或者一个tab键
[[:punct:]] :表示任意单个符号
[[:alpha:]] :表示任意单个字母,包括大小写
[[:alnum:]] :表示任意单个0到9的数字或任意单个字母,包含大小写
[^]:表示非的意思。
例如:[^abc]既表示除了abc外的任意单个字符
2)次数匹配元字符:用于实现指定其前面的字符所能够出现的次数
*: 表示其前面的字符可以出现任意次(0到无穷次)
例如:x*y (表示x可以出现任意次)
\?: 0次或1次,表示它前面的字符是可有可无的
例如:x\?y (表示x可以出现0次或一次)
\{m\}: m次,表示它前的字符要出现m次
例如:x\{2\}y (表示x出现2次)
\{m,n\}: 至少m次,至多n次
例如:x\{2,5\}y (表示x出现2到5次)
\{m,\}:表示其前面的字符出现至少m次 (其中至少一次可以用\+表示)
\{0,n\}: 表示其前面的字符出现至多n次
.*:表示任意个数的任意字符
需要注意的是grep工作于贪婪模式的,如果你不知道它是什么也没关系,你可以这样认为,
就是在整个表达式匹配成功的前提下,尽可能多的匹配,也就是所谓的“贪婪”,
通俗点讲,就是看到想要的,有多少就捡多少,除非再也没有想要的了。
3)位置锚定:分为行锚定和词锚定
行锚定:
^: 行首锚定;
写在模式最左侧 用法 : ^a 表示以字母a开头的行
$: 行尾锚定:
写在模式最右侧 用法 :a$ 表示以字母a结尾的行
词锚定:不包含特殊字符的连续字符组成的串叫单词
\<: 词首,出现于单词左侧,\b
用法 : \<char 表示以char开头的单词
\>: 词尾,出现于单词右侧, \b
用法 : char\> 表示以char结尾的单词
4)分组:
\(\) 分组符号
例如:\(ab\)*
分组中的模式匹配到的内容,可由正则表达式引擎记忆在内存中,之后可被引用
\#: 引用第n个括号所匹配到的内容,而非模式本身
这里有必要解释下引用:这里的n是指分组的编号,这个编号规则是根据左括号的顺序编的,自左向右;而其内容为该左括号和与之匹配右括号中间的字符串。
例如:
\(a\(b\(c\)\)\).*\1 指引用第1个括号之间的内容,既这些内容 a\(b\(c\)\)
\(a\(b\(c\)\)\).*\2 指引用第2个括号之间的内容,既这些内容 b\(c\)
\(a\(b\(c\)\)\).*\3 指引用第3个括号之间的内容,既这些内容 c
为了让大家更容易理解下面我们做一个简单的例题:对\(ab\?c\).*\1 进行匹配
abcmnaaa
abcmnabc
abcmnac
acxyac
解题思路:这题可以将题目分成3部分,分别为引用部分\(ab\?c\),中间部分.*,以及指定引用部分\1;
先看第一部分 中的\?,这里表示其之前的字符可有可无,所以该部分为ac或者abc;
再看第二部分.*表示任意长度的任意字符;
再看第三部分\1表示引用第1个括号之间的内容;
因此这题可有理解为ac.*ac 或者abc.*abc.所以符合条件是第二个和第四个。
3、grep的命令选项:【option】
在这里的话,我主要列了几个我们以后比较常用的几个选项,并不是它的全部哦,如果需要了解更多的选项建议大家使用man命令查找。
-v: 反向选取,只显示不符合模式的行
-o: 仅显示匹配到的字符串,而非字符串所在的行
-i: ignore-case,匹配时忽略字符的大小写
-E: 将模式 PATTERN 作为一个扩展的正则表达式来解释 (具体方法我将会在下面的egrep中介绍)
-A #:显示匹配到的行时,顺便显示后面的#行(#表示数值)
-B #:显示匹配到的行时,顺便显示前面的#行
-C #:显示匹配到的行时,顺便显示前后的#行
4、以上就是grep的一些基本知识,当然想要巩固这些知识点的话做练习是非常必要。下面我们就通一些练习对grep进行实际的操作。
(1)、显示/proc/meminfo文件中以大写或小写S开头的行;
这里的话我们有多种做法,可以通过更改grep的选项i,也可以元字符的更改来实现。2种方法都行。
#grep -i "^s" /proc/meminfo #grep "^[Ss]" /proc/meminfo
(2)、显示/etc/passwd中以nologin结尾的行;
#grep "nologin$" /etc/passwd
(3)、显示/etc/passwd中,以r开头的字符而后跟了任意单个字符的行;
#grep "^r." /etc/passwd
(4)、显示/etc/passwd中,以r开头后跟了o,o出现任意次的行;
# grep "^ro*" /etc/passwd
(5)、显示/etc/passwd文件中,r后跟了任意长度任意字符后跟了h的行
#grep "r.*h" /etc/passwd
(6)、显示/etc/passwd中,r后跟了o,o出现0次或者1次的行;
#grep "ro\?" /etc/passwd
(7)、显示/etc/passwd中,r后跟了o,o出现至少1次至多2次的行;
#grep "ro\{1,2\}" /etc/passwd
(8)、显示/etc/passwd中,r后跟了o,o只出现2次的行;
#grep "ro\{2\}" /etc/passwd
(9)、显示/etc/passwd中,匹配root这个单词的行;(因为匹配时一个完整的单词,因此词首和词尾都必须锚定)
#grep "\<root\>" /etc/passwd
(10)、找出/etc/passwd文件中的一位数或两位数,并只显示数字本身;(数字也是独立的,需要前后锚定,2种方法都行)
#grep -o "\<[0-9][0-9]\?\>" /etc/passwd #grep -o "\<[0-9]\{1,2\}\>" /etc/passwd
(11)、/boot/grub/grub.conf中以至少一个空白字符开头的行;
#grep "^[[:space:]]\{1,\}" /boot/grub/grub.conf
(11)、显示/etc/rc.d/rc.sysinit文件中,以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行;
#grep "^#[[:space:]]\{1,\}[^[:space:]]\{1,\}" /etc/rc.d/rc.sysinit
(12)、找出当前系统上其用户名和默认shell相同的用户;(这一题略微有点复杂哦,运用的是 分组引用的方法)
#grep "^\([[:alnum:]]\{1,\}\):.*\1$" /etc/passwd
二、egrep的介绍
egrep是指扩展的grep,它的用法与grep比较相似,只是它的一些转义字符\在这里不需要使用,
所以有些跟上面的使用一样的我就不详细介绍了。
1、grep的语法格式
egrep 'PATTERN' FILE... 它相当于 grep -E 'PATTERN' FILE...
2、扩展正则表达式的元字符
1)字符匹配:(这里的格式跟grep中的一样)
.
[]
[^]
2)次数匹配:(除了*和grep一样外,其他的都不需要转义字符\)
*:表示其前面的字符出现任意次
?: 表示其前面的字符出现0次或1次
+: 表示其前面的字符出现至少1次;
{m}: 表示其前面的字符出现m次
{m,n}: 表示其前面的字符出现至少m次,至多n次
{m,}:表示其前面的字符出现至少出现m次
{0,n}:表示其前面的字符出现至多n次
3)锚定:(锚定跟grep都一样)
^ :行首
$ :行尾
\<, \b :词首
\>, \b :词尾
4)分组:
() :分组无需转义字符
\# :\1, \2, \3引用
5)或者:(egrep和grep最大的不同是它可以使用或者)
a|b: a或者b
为了更好的说明他的使用方法我们来看一个例子
例如:conC|cat 其表示的是conC或cat的意思
而con(C|c)at 表示的才是concat或conCat的意思
3、egrep的一些常用选项
-v: 反向选取,只显示不符合模式的行
-o: 仅显示匹配到的字符串,而非字符串所在的行
-i: ignore-case,匹配时忽略字符的大小写
-A #:显示匹配到的行时,顺便显示后面的#行(#表示数值)
-B #:显示匹配到的行时,顺便显示前面的#行
-C #:显示匹配到的行时,顺便显示前后的#行
4、 练习:使用扩展的正则表达式 (这里我们主要就对或的用法进行练习)
(1)、显示当前系统上root、fedora或user1用户的信息;
# egrep "^(root|fedora|user1):" /etc/passwd
(2)、找出/etc/rc.d/init.d/functions文件中某单词后跟一组小括号“()”行;(由于这里的小括号是想表示他本身的意思所以需要进行转义)
# egrep -o "\<[[:alnum:]]+\>\(\)" /etc/rc.d/init.d/functions
(3)、使用echo命令输出一个路径,而后使用grep取出其基名;
# echo "/etc/sysconfig/" | egrep -o "[[:alnum:]]+/?" # echo "/etc/sysconfig/" | egrep -o "[^/]+/?$" | cut -d/ -f1
(4)、找出ifconfig命令结果中的1-255之间的数字;
# ifconfig | egrep -o "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>"
(5)显示/etc/inittab中包含 halt 或 Single的行
# egrep "(halt|Single)" /etc/inittab
好了,以上这些就是今天我所要讲的内容,可能很多地方讲的不是那么详细,有些地方也可能讲的不是很恰当,因此我很希望能够得到大家的补充以及修改指正,谢谢大家!