grep命令详解
grep命令用于在文本中查找指定的字符串。可以把grep理解为字符查找工具,grep是一个可以利用正则表达式进行全局搜索的工具,并将搜索出来的行打印出来。当然,不使用正则表达式也可以使用grep,但是grep与正则结合在一起,功能会更加强大。
我们先来看一个简单的例子,认识一下grep,我们从一个文本文件中找出包含test字符串的行:
[root@localhost shell]# cat testgrep zsy test zsythink www.zsythink.net TEST 123 Zsy's articles grep Grep abc abc123abc 123zsy123 [root@localhost shell]# grep "test" testgrep zsy test
上例中表示使用grep命令,在文件中搜索包含"test"字符串的行。并将包含"test"字符串的行打印出来。于是,文件的第一行被打印出来,默认情况下,grep是区分大小写的,所有TEST没有被打印。
如果我们在搜索字符串的时候,想要不区分大小写,可以通过使用 -i 参数,即可在搜索时不区分大小写,示例如下:
[root@localhost shell]# grep -i "test" testgrep zsy test TEST 123
由于testgrep文件行数较少,所有可以数过来时第一行和第五行包含test字符串,但是如果文件很大,成千上万行。想要指定文本哪行包含test字符串,我们可以使用 -n 参数。表示显示打印出的行在文本中的行号:
[root@localhost shell]# grep -i -n "test" testgrep 1:zsy test 5:TEST 123
在centos6系统中,我们使用grep在文本中搜索的行被打印出来,但是匹配到的关键字没有以高亮度显示,如果我们想要高亮度显示匹配到的关键字。我们可以使用 --color选项,使用 --color 和使用 --color=auto的效果相同。在centos7中,系统默认为grep命令配置了别名,不用显式指定 --color 选项。默认高亮显示被匹配到的关键字,可以通过alais命令查看别名:
[root@localhost shell]# alias alias cp='cp -i' alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias rm='rm -i'
在testgrep文本中,一共有两行包含了 test 字符串。如果我们不关心包含test行的内容,只想知道有多少行包含test字符串,这时候我们可以使用 -c 参数。
[root@localhost shell]# grep -i "test" testgrep zsy test TEST 123 [root@localhost shell]# grep -i -c "test" testgrep 2
以上的示例中,包含关键词的行都被打印出来了,打印的是整行内容。如果只想看到被匹配的关键字,而不需要整行的内容。我们可以使用 -o 参数来实现只打印匹配到的关键字,而不打印整行,示例如下:
[root@localhost shell]# grep -i -o "test" testgrep test TEST
需要注意的是,-o参数会把每个匹配到的关键字都单独在一行内进行输出,示例如下:
[root@localhost shell]# grep -i "123" testgrep TEST 123 abc123abc 123zsy123 [root@localhost shell]# grep -i -o "123" testgrep 123 123 123 123 [root@localhost shell]# grep -i -n -o "123" testgrep 5:123 9:123 10:123 10:123
如上所示:当没有使用 -o 选项时,包含123字符串的行都被打印出来。当同一行包含多个123时,所在行会被打印出来。对应的关键字也会高亮显示。当使用了 -o 选项时,每个匹配到的关键字都会被单独打印到一行中去。在上例中,第三个和第四个123都是属于第十行的文本。
在我们使用grep命令搜索文本时,往往有这种需求。在找到对应的关键字时,同时需要显示关键字附近的信息。我们通过一个场景来了解一下。我们在一个以下一个文本中找出年龄为18的人。
[root@localhost shell]# cat testgrep1 姓名:小泽老师 年龄:18 评分:98 姓名:苍老师 年龄:32 评分:99 姓名:波多老师 年龄:18 评价:95 [root@localhost shell]# grep "年龄:18" testgrep1 年龄:18 年龄:18
上例中只是匹配到了年龄,但是并不知道姓名,因为姓名和年龄并不在同一行。这时我们可以使用 -B选项,显示符合条件的行之前的行,B可以理解为before之意。示例如下:
[root@localhost shell]# grep -B1 "年龄:18" testgrep1 姓名:小泽老师 年龄:18 -- 姓名:波多老师 年龄:18
如上图所示,包含年龄18的行被输出了。同时符合条件的前一行也被输出了,上例中的 -B1选项就是表示显示符合条件的行同时还显示之前的一行。同样的 -B5 代表显示之前的5行 -B3 代表显示之前的3行,-B选项后面必须跟数字,否则会报错。
与 -B 选项对应的是 -A 选项 B有before之意,A有after之意。所以,-A表示显示符合条件行的同时,还要显示之后的行。
介绍了 -A和-B选项。可以再看看 -C ,-C可以理解为 -A 和 -B 的结合。-C表示显示符合条件的行的同时,还要显示前后的行。如 -C1 表示打印符合条件行的同时,也打印出之前的一行和之后的一行。C有context(上下文之意)。示例如下:
[root@dm shell]# grep -C1 "年龄:18" testgrep1 姓名:小泽老师 年龄:18 评分:98 -- 姓名:波多老师 年龄:18 评价:95
这样,就可以看到年龄18岁的人所有信息了。
有的时候,我们需要精准匹配,上述的方法显然无法满足。示例如下:
[root@dm shell]# cat testgrep zsy test zsythink www.zsythink.net TEST 123 Zsy's articles grep Grep abc abc123abc 123zsy123 [root@dm shell]# grep "zsy" testgrep zsy test zsythink www.zsythink.net 123zsy123
我们在文本中搜索zsy字符串的时候,zsy zsythink 123zsy123所在的行都被匹配到了。因为zsythink中包含了zsy,所以也被匹配到了。但是如果想要精确匹配zsy字符串的时候,上例中的方法就无法做到了。所谓精确匹配,就是zsy作为单独一个词存在,而不是存在于某个字符串中。 那么这种需求我们该如何实现呢,使用 -w 选项可以满足我们的需求。示例如下:
[root@dm shell]# grep "zsy" testgrep zsy test zsythink www.zsythink.net 123zsy123 [root@dm shell]# grep -w "zsy" testgrep zsy test
如上例所示,使用了 -w 选项之后,只有zsy作为一个单独的单词而存在的时候,才会被匹配到。zsy包含于某个字符串时,不会被匹配到。这就是所谓的精准匹配, -w有word之意。表示搜索一个字符串作为一个独立的单词时才会被匹配到。
有些时候,我们需要反向查找。比如查找不包含某些字符串的行,这个时候,我们需要用到 -v 选项。示例如下:
[root@dm shell]# cat testgrep zsy test zsythink www.zsythink.net TEST 123 Zsy's articles grep Grep abc abc123abc 123zsy123 [root@dm shell]# grep -i -v "zsy" testgrep TEST 123 grep Grep abc abc123abc
上例中表示查找不包含zsy字符串的行。
有的时候,我们可能需要从多个目标中匹配。什么意思呢,我们通过示例来看:
[root@dm shell]# grep -e "abc" -e "test" testgrep zsy test abc abc123abc
上例中,我们同时在文本中搜索abc字符串和test字符串。包含这两个字符串的任意一个都会被打印出来,就像上面的示例一样。使用 -e 选项可以同时匹配多个目标,多个目标之间存在或联系。即匹配其中任意一个都算匹配成功。
在写脚本时,有时只想利用grep判断文本中是否存在某个字符串。只关心有没有匹配到,而不关心匹配到的内容。只关心有或没有,这时,我们就可以使用grep的静默模式。示例如下:
[root@dm shell]# grep -q "test" testgrep [root@dm shell]# echo $? 0 [root@dm shell]# grep -q "ttttttt" testgrep [root@dm shell]# echo $? 1
当使用 -q 选项时,表示使用grep静默模式,静默模式下grep不会输出任何信息。无论是否匹配到指定的字符串,都不会输出任何信息。所以,我们需要配合 echo $? 命令,查看命令的执行状态。如果返回值为0,证明上一条grep命令匹配到了指定的字符串。如果返回为1,证明上一条grep命令没有匹配到指定的字符串。
在开头我们说了,grep可以利用正则表达式进行搜索。但是之前的举例中,grep都没有使用正则表达式。只是纯粹的查找一些字符串,这次我们使用grep命令配合正则表达式,来查找我们想要的目标。比如,我们想找到一个文本中的合法邮箱。
[root@dm shell]# cat testgrep2 sdasfas zsythink@yeah.net asdsadfasffsfsfs@ @dwdaj [root@dm shell]# grep -E "^([[:alnum:]]{6,18})@([[:alnum:]]{1,20}).(com(.cn)?|org|edu|net|mil|gov|info)$" testgrep2 zsythink@yeah.net
上例中我们使用了扩展的正则表达式,而不是基础的正则表达式。所有,上述命令中,我们使用了 -E 选项。
在使用了 -E 选项时,grep才支持扩展正则表达式,不适用 -E 选项时,grep默认只支持基本正则表达式。
另:不同的开发语言中,正则表达式的规则可能略有不同。我们使用grep时,可以使用 -P 选项,指明使用perl兼容的正则表达式。示例如下:
[root@dm shell]# grep -P "[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+" testgrep2 zsythink@yeah.net
grep的常用选项已经总结完了。其实,除了grep命令,还有egrep和fgrep命令
grep : 支持基本正则表达式
egrep : 支持扩展正则表达式,相当于grep -E
fgrep : 不支持正则表达式,只能匹配写死的字符串。但是速度快,效率高,fastgrep
总结
grep的常用选项总结如下:
--color=auto或者--color:对匹配的文本着色显示
-i : 搜索的时候忽略大小写
-n : 显示结果所在行号
-c : 统计匹配到的行数,注意时匹配到的总行数,不是匹配到的次数
-o : 只显示符合条件的字符串,但是不整行显示,每个符合条件的字符串单独显示一行
-v : 输出不带关键字的行(反向查询,反向匹配)
-w : 匹配整个单词,如果是字符串中包含这个单词,则不做匹配
-Ax : 在输出的时候包含结果所在行之后的指定行数,这里指之后的x行
-Bx : 在输出的时候包含结果所在行之前的指定行数,这里指之后的前行
-Cx : 在输出的时候包含结果所在行之前和之后的指定行数,这里指之前和之后的x行
-e : 实现多个选项的匹配,逻辑 or 关系
-q : 静默模式,不输出任何信息。然后使用echo $?查看是否匹配到,0表示匹配到,1表示没有匹配到。
-P : 表示使用兼容perl的正则引擎
-E : 使用扩展正则表达式,而不是基本正则表达式,相对于使用egrep