Linux grep命令详解

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

原文地址:https://www.cnblogs.com/jkin/p/11356510.html