grep介绍
我们了解cut命令是对一个文本进行列的匹配,但是这种方法在我们的实际操作中显得过于啰嗦,因此我们选择使用了grep命令。grep(Globally
search a Regular Expression and Print)是一款文本过滤工具,可以使用它对目标文本进行**逐行**的匹配检查,然后将匹配到的行打印出来。
如下:
[root@localhost ~]# cat test.file
aaa
bbb
ccc
abc
fff
ddd
add
[root@localhost ~]# cat test.file |grep a
aaa
abc
add
grep相关选项用法
选项 | 注释 |
---|---|
–color=auto | 对匹配到的文本着色显示 |
-v | 显示不被pattern匹配到的行 |
-i | 忽略字符大小写 |
-n | 显示匹配的行号 |
-c | 统计匹配的行数 |
-o | 仅显示匹配到的字符串 |
-q | 静默模式,不输出任何信息 |
-A # | after, 后#行 |
-B # | before, 前#行 |
-C # | context, 前后各#行 |
-e | 实现多个选项间的逻辑or关系 |
-w | 匹配整个单词 |
-E | 使用ERE |
现在我们依次对grep的选项进行解释:
–color=auto 对匹配到的文本着色显示(由于该编辑器上无法显示颜色,我们以linux系统下的截图进行说明)
-v 显示不被pattern匹配到的行
[root@localhost ~]# cat test.file
aaa
bbb
ccc
abc
fff
ddd
add
[root@localhost ~]# cat test.file |grep -v a
bbb
ccc
fff
ddd
-i 忽略字符大小写
[root@localhost ~]# cat test.file
aaa
AAA
bbb
ccc
abc
fff
ddd
add
[root@localhost ~]# cat test.file |grep -i a
aaa
AAA
abc
add
-n 显示被匹配到的行数
[root@localhost ~]# cat test.file
aaa
AAA
bbb
ccc
abc
fff
ddd
add
[root@localhost ~]# cat test.file |grep -n a
1:aaa
5:abc
8:add
-c 统计匹配的行数
[root@localhost ~]# cat test.file |grep -c a
3
-o 仅仅显示匹配到的字符串(不显示其他)
[root@localhost ~]# cat test.file |grep -o a
a
a
a
a
a
-q 静默模式,不输出任何信息 (无论是否匹配到,都不输出)
该模式适用于shell脚本编写时,用法 = /dev/null
-A #: 显示匹配到的行,同时显示后#行(after)
[root@localhost ~]# grep -A3 root /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
-B #: 显示匹配到的行,同时显示前#行(before)
[root@localhost ~]# grep -B3 wangcai /etc/passwd
ntp:x:38:38::/etc/ntp:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
magedu:x:1000:1000:magedu:/home/magedu:/bin/bash
wangcai:x:1001:1001::/home/wangcai:/bin/bash
-C #:显示匹配到的行,同时显示前后#行
[root@localhost ~]# grep -C3 magedu /etc/passwd
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
magedu:x:1000:1000:magedu:/home/magedu:/bin/bash
wangcai:x:1001:1001::/home/wangcai:/bin/bash
xiaoqiao:x:1002:1002::/home/xiaoqiao:/bin/bash
zhangsan:x:1005:1010::/home/zhangsan:/bin/bash
-e:实现多个选项间的逻辑or关系
相当于“或”的意思
[root@localhost ~]# echo a b c d e A B |grep -o -e a -e B
a
B
-w:匹配整个单词
[root@localhost ~]# grep -w magedu /etc/passwd
magedu:x:1000:1000:magedu:/home/magedu:/bin/bash
注:【-w 匹配的是一整个单词,而单词里包含你所搜索的关键字的单词则不会被匹配出来】
正则表达式
正则表达式是由一类特殊字符及文本字符所编写的模式,其中有些字符不表示字符的字面意义,而表示控制或统配的功能。
包括基本正则表达式(BRE)和扩展表达式(ERE)。
grep工具支持基本正则表达式,egrep支持扩展正则表达式,而且grep 的-E 选项其实就是egrep。
基本正则表达式元字符
元字符分类:字符匹配、次数匹配、位置锚定、分组
字符匹配
选项 | 注释 |
---|---|
. | 匹配任意单个字符 |
[ ] | 匹配指定范围内的任意单个字符 |
[^] | 匹配指定范围外的任意单个字符 |
[:digit:] | 十进制数字 |
[:lower:] | 小写字母 |
[:upper:] | 大写字母 |
[:alnum:] | 字母和数字 |
[:alpha:] | 代表任何英文大小写字符 |
[:blank:] | 空白字符(空格和制表符) |
[:space:] | 水平和垂直的空白字符 |
[:punct:] | 标点符号 |
根据以上选项来进行实验:
次数匹配
选项 | 注释 |
---|---|
* | 匹配前面的字符任意次,包括0次 |
.* | 任意长度的任意字符 |
\? | 匹配其前面的字符0或1次 |
\+ | 匹配其前面的字符至少1次 |
\{m\} | 匹配前面的字符m次 |
\{m,n\} | 匹配前面的字符至少m次,至多n次 |
\{,n\} | 匹配前面的字符至多n次 |
\{m,\} | 匹配前面的字符至少m次 |
几个实验来分别解释:
注:【在默认的情况下,正则表达式是工作在贪婪模式下,即没有自动限制的功能,能匹配多少就匹配多少,在使用的时候需根据具体情况加入选项。】
位置锚定
选项 | 注释 |
---|---|
^ | 行首锚定,用于模式的最左侧 |
$ | 行尾锚定,用于模式的最右侧 |
^PATTERN$ | 用于模式匹配整行 |
^$ | 空行 |
^[[:space:]]*$ | 空白行 |
\< 或 \b | 词首锚定,用于单词模式的左侧 |
\> 或 \b | 词尾锚定;用于单词模式的右侧 |
\<word\> | 匹配整个单词 |
例如:1、显示/etc/passwd文件中不以/bin/bash结尾的行
[root@localhost ~]# grep -v "/bin/bash$" /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
解题思路:$表示以/bin/bash
结尾的行,-v
表示显示不被匹配到的行,两个选项配合。即得出不以/bin/bash结尾的行。
2、显示/proc/meminfo文件中以大小s开头的行
[root@localhost ~]# grep -i "^s" /proc/meminfo
SwapCached: 0 kB
SwapTotal: 3905532 kB
SwapFree: 3905532 kB
解题思路:-v
表示忽略大小写,^
在这里表示行首锚定
或者:
[root@localhost ~]# grep "^[sS]" /proc/meminfo
SwapCached: 0 kB
SwapTotal: 3905532 kB
SwapFree: 3905532 kB
解题思路:[]
表示匹配范围内的任意字符,^
表示行首锚定
3、显示用户rpc默认的shell程序
[root@localhost ~]# grep "^rpc\>" /etc/passwd
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
[root@localhost ~]# grep "^rpc\>" /etc/passwd |cut -d: -f7
/sbin/nologin
解题思路:^
表示以rpc开头,\>
表示c词尾锚定,可以直接匹配出rpc用户所属的行,然后用cut
提取出它的默认程序。
4、找出/etc/passwd中的两位或三位数
[root@localhost ~]# grep -o "\<[[:digit:]]\{2,3\}\>" /etc/passwd
解题思路 : [[:digit:]]
表示匹配 [0-9] 的数字,\{2,3\}
表示匹配前面的字符至少2次,至多3次。即/etc/passwd
中的两位或三位数。-o
表示只显示匹配到字符。
5、显示CentOS7的/etc/grub2.cfg文件中,至少以一个空白字符开头的且后面存非空白字符的行。
[root@localhost ~]# grep "^[[:space:]]\+[^[:space:]]" /etc/grub2.cfg
解题思路 : ^[[:space:]]
表示以空白符开头,[^[:space:]]
表示匹配非空的字符,注意与前一个区别开。\+
表示匹配前面的字符至少一次。即题目中要求的至少以一个空白字符开头。
6、找出“netstat -tan”命令的结果中以‘LISTEN’后跟任意多个空白字符结尾的行
[root@localhost ~]# netstat -tan |grep "LISTEN[[:space:]]*$"
解题思路 : [[:space:]]
表示空白字符,*
表示匹配其前面的字符任意次,$
表示以空白字符结尾。
7、显示CentOS7上所有系统用户的用户名和UID
[root@localhost ~]# cat /etc/passwd|cut -d: -f1,3| grep "\<[[:digit:]]\{1,3\}\>"
解题思路 :先使用cut
命令取出所有用户的用户名和UID,因为在CentOS7上系统用户的UID 的使用范围是1-999,所以 [:digit:]
的范围可以确定在\{1,3\}
之间,最后使用\<\>确定匹配的是整个数字。
分组
分组是指将一个或多个字符捆绑在一起,当做一个整体来处理,其符号为:\(\)
如:\(xy\)*ab
表示将xy看做一个整体,可以出现任意次。
注意 :
1、 分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为:\1, \2, \3……
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符,如:
\(ab\+(xy\)*\)中,\1 表示(ab\+(xy\)* ,\2 表示 xy
2、后向引用:引用前面的分组括号中的模式所匹配到的字符,而非模式本身。
选项 | 注释 |
---|---|
\(\) | 用括号表示要引用的内容 |
\1,\2,\3 | 后向引用 |
a\|b | 表示或的意思,即a或b |
例如:
练习题8:添加用户bash、testbash、basher、sh、nologin(其shell为/sbin/nologin),找出/etc/passwd用户名同shell名的行
[root@localhost ~]# grep "\(^\<.*\>\).*/\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
nologin:x:1014:1020::/home/nologin:/sbin/nologin
bash:x:1015:1021::/home/bash:/bin/bash
对比图:
[root@localhost ~]# grep "^\(\<.*\>\):.*\1$" /etc/passwd
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
nologin:x:1014:1020::/home/nologin:/sbin/nologin
bash:x:1015:1021::/home/bash:/bin/bash
sh:x:1018:1018::/home/sh:/bin/bash
解题思路 : 添加用户过程省略。看题目中找出文件中用户名同shell名的行,并没有给出关键字匹配,意味着这不能用一般的匹配方法。^\<.*\>
表示匹配在行首以任意字符任意长度的一整个单词或字符串。\(^\<.*\>\)
表示分组,将它作为一个整体,使用\1
后向引用这个结果,从而达到题目中用户名同shell名一样的行。:.*/
表示 : 后是任意长度任意字符,重点注意其中的 / 。
题目中有个陷阱,看对比图中,因为shell以 / 为分隔,如果不加,会将sh:x:1018:1018::/home/sh:/bin/bash
也匹配出来,如此不符合题目要求。
9、仅利用df和grep和sort,取出磁盘各分区利用率,并从大到小排序。
[root@localhost ~]# df |grep sd |grep -o "\<[[:digit:]]\{1,3\}\b%" |sort -nr
解题思路 : df |grep sd
表示只匹配磁盘的分区,\<[[:digit:]]\{1,3\}\b%
表示匹配只有1-3位并且后跟%的数字,将各磁盘的分区利用率提取出来,然后使用sort
进行排序。
扩展正则表达式
使用语法:grep -E ” PATTERN ” file…
egrep ” PATTERN ” file…
扩展正则表达式的匹配方式基本与基本正则表达式相同,只是在进行符号转义的时候,不需要 \ 来进行转义。除去\<, \b ,>三种特殊情况。
字符匹配
选项 | 注释 |
---|---|
. | 匹配任意单个字符 |
[ ] | 匹配指定范围内的任意单个字符 |
[^] | 匹配指定范围外的任意单个字符 |
次数匹配
选项 | 注释 |
---|---|
* | 匹配前面的字符任意次,包括0次 |
.* | 任意长度的任意字符 |
? | 匹配其前面的字符0或1次 |
+ | 匹配其前面的字符至少1次 |
{m} | 匹配前面的字符m次 |
{m,n} | 匹配前面的字符至少m次,至多n次 |
{,n} | 匹配前面的字符至多n次 |
{m,} | 匹配前面的字符至少m次 |
位置锚定
扩展正则表达式的位置锚定和基本正则表达式相同,不在重复说明。
分组
选项 | 注释 |
---|---|
() | 用括号表示要引用的内容,不需要转义 |
\1,\2,\3 | 后向引用 |
a|b | 表示或的意思,即a或b |
练习题:
1、显示三个用户root、mage、wang的UID和默认shell。
[root@localhost ~]# egrep "^(root|mage|wang):" /etc/passwd
2、找出/etc/rc.d/init.d/functions文件中行首为某单词(包括下划线)后面跟一个小括号的行。
# egrep -o "^[[:alpha:]]*_*.*\(\)" /etc/rc.d/init.d/functions
解题思路 :^[[:alpha:]]*_*.*
表示匹配行首为单词开头或者下划线开头或者单词中包含下划线的行,其中*
匹配其前面的字符0次或多次,.*
表示任意字符任意长度。\(\)
【注意了~】这部分本编也是纠结了很长时间才才明白,虽然说在扩展正则表达式中括号不需要转义符来表示,但是在这里,括号有另外的意思,表示分组。所以想要表示括号的本义,还需要转义符来进行转换。
3、使用egrep取出/etc/rc.d/init.d/functions中其基名
# echo /etc/rc.d/init.d/functions |egrep -o "[[:alpha:]]+$"
解题思路 : [[:alpha:]]+
表示匹配任意字母至少一次;$
表示位置锚定在行尾;-o
表示只显示匹配到的字符
4、使用egrep取出上面路径的目录名
# echo /etc/rc.d/init.d/functions |egrep -o "^.*/"|egrep -o "^.*[^/]"
解题思路 : ^.*/
表示匹配任意以 / 结束的字符;^.*[^/]
表示只显示除了 / 以外的字符。
5、利用扩展正则表达式分别表示0-9、10-99、100-199、200-249、250-255
[root@localhost ~]# echo {0..255}|egrep -o "\<[0-9]\>"
[root@localhost ~]# echo {0..255}|egrep -o "\<[0-9]{2}\>"
[root@localhost ~]# echo {0..255}|egrep -o "\<1[0-9]{2}\>"
[root@localhost ~]# echo {0..255}|egrep -o "\<2[0-4][0-9]\>"
[root@localhost ~]# echo {0..255}|egrep -o "\<25[0-5]\>"
6、统计last命令中以root登录的每个主机IP地址登录次数
# last | egrep -o "^root.*\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>"|tr -s ' ' |cut -d ' ' -f3|sort|uniq -c
解题思路 : IP地址表示方法由第5题得出。
7、显示ifconfig命令结果中所有IPv4地址
# ifconfig |egrep -o "\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>"
8、将此字符串:welcome to magedu linux 中的每个字符
去重并排序,重复次数多的排到前面
[root@localhost ~]# echo welcome to magedu linux |grep -o "[[:alpha:]]"|sort|uniq -c|sort -nr
3 e
2 u
2 o
2 m
2 l
1 x
1 w
1 t
1 n
1 i
1 g
1 d
1 c
1 a
解题思路 : -o "[[:alpha:]]"
表示只显示每个被匹配到的字符,意义上说相当于把每个字母拆分来显示成行。然后使用sort
排序后,可以用uniq -c
去重并统计每行重复的次数。