linux命令三剑客之grep

linux命令三剑客(grep、sed、awk),日常开发中离不开的几大命令,尤其是几个命令结合使用时其功能更强大,可以大大提升服务器操作效率。

grep

grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

Unix的grep家族包括grep、egrep和fgrep。egrep和fgrep的命令只跟grep有很小不同。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。

grep基本使用

grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 ‘搜寻字符串’ 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有’搜寻字符串’内容的那一行
–color=auto :可以将找到的关键词部分加上颜色的显示

从/etc/passwd,将有出现root的行取出来

1
2
3
4
5
# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash

# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash

从/etc/passwd,将有出现 root 的行取出来,同时显示这些行在/etc/passwd的行号

1
2
# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash

在关键字的显示方面,grep 可以使用 –color=auto 来将关键字部分使用颜色显示。但是如果每次使用 grep都得要自行加上–color=auto 又显的很麻烦,此时可以用alias来处理一下,可以在 ~/.bashrc 内加上:alias grep='grep --color=auto'再以source ~/.bashrc来立即生效即可。这样每次运行grep命令他都会自动帮我们加上颜色显示。

从/etc/passwd,将没有出现root的行取出来

1
2
3
4
# grep -v root /etc/passwd
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin

从/etc/passwd,将没有出现rootnologin的行取出来

1
2
# grep -v root /etc/passwd | grep -v nologin
sync:x:4:65534:sync:/bin:/bin/sync

用 dmesg 列出核心信息,再以 grep 找出内含 eth 那行,要将捉到的关键字显色,且加上行号来表示:

1
2
3
4
5
6
7
# dmesg | grep -n --color=auto 'eth'
1133:[ 12.629105] igb 0000:04:00.0: added PHC on eth0
1135:[ 12.629110] igb 0000:04:00.0: eth0: (PCIe:5.0Gb/s:Width x4) 00:25:90:c2:46:18
1136:[ 12.629183] igb 0000:04:00.0: eth0: PBA No: 106100-000
1148:[ 12.681007] igb 0000:04:00.1: added PHC on eth1
1150:[ 12.681012] igb 0000:04:00.1: eth1: (PCIe:5.0Gb/s:Width x4) 00:25:90:c2:46:19
1151:[ 12.681085] igb 0000:04:00.1: eth1: PBA No: 106100-000

用 dmesg 列出核心信息,再以 grep 找出内含 eth 那行,在关键字所在行的前两行与后三行也一起捉出来显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# dmesg | grep -n -A3 -B2 --color=auto 'eth'
1131-[ 12.591633] nouveau 0000:06:00.0: NVIDIA GK208B (b060b0b1)
1132-[ 12.591676] nouveau 0000:06:00.0: irq 53 for MSI/MSI-X
1133:[ 12.629105] igb 0000:04:00.0: added PHC on eth0
1134-[ 12.629108] igb 0000:04:00.0: Intel(R) Gigabit Ethernet Network Connection
1135:[ 12.629110] igb 0000:04:00.0: eth0: (PCIe:5.0Gb/s:Width x4) 00:25:90:c2:46:18
1136:[ 12.629183] igb 0000:04:00.0: eth0: PBA No: 106100-000
1137-[ 12.629185] igb 0000:04:00.0: Using MSI-X interrupts. 8 rx queue(s), 8 tx queue(s)
1138-[ 12.629454] igb 0000:04:00.1: irq 55 for MSI/MSI-X
1139-[ 12.629487] igb 0000:04:00.1: irq 55 for MSI/MSI-X
--
1146-[ 12.629543] igb 0000:04:00.1: irq 62 for MSI/MSI-X
1147-[ 12.629551] igb 0000:04:00.1: irq 63 for MSI/MSI-X
1148:[ 12.681007] igb 0000:04:00.1: added PHC on eth1
1149-[ 12.681010] igb 0000:04:00.1: Intel(R) Gigabit Ethernet Network Connection
1150:[ 12.681012] igb 0000:04:00.1: eth1: (PCIe:5.0Gb/s:Width x4) 00:25:90:c2:46:19
1151:[ 12.681085] igb 0000:04:00.1: eth1: PBA No: 106100-000
1152-[ 12.681086] igb 0000:04:00.1: Using MSI-X interrupts. 8 rx queue(s), 8 tx queue(s)
1153-[ 12.703425] nouveau 0000:06:00.0: bios: version 80.28.a6.00.48
1154-[ 12.703901] nouveau 0000:06:00.0: priv: HUB0: 085014 ffffffff (1e70820b)

根据文件内容递归查找目录

1
2
3
# grep 'mysql' *        #在当前目录搜索带'mysql'行的文件
# grep -r 'mysql' * #在当前目录及其子目录下搜索'mysql'行的文件
# grep -l -r 'mysql' * #在当前目录及其子目录下搜索'mysql'行的文件,但是不显示匹配的行,只显示匹配的文件

这几个命令很有用,是查找文件的利器

grep与正规表达式

字符的搜索: 如果想要搜寻testtaste这两个单词,可以发现到,其实她们有共通的 ‘t?st’ 存在,这个时候,我可以这样来搜索

1
2
3
# grep -n 't[ae]st' regular_express.txt
8:I can't finish the test.
9:Oh! The soup taste good.

[] 里面不论有几个字符,他都仅代表某一个字符,所以,上面的例子说明需要搜索的是tasttest两个字符串。

字符的反向选择[^],如果想要搜索到有oo的行,但不想要oo前面有g,如下:

1
2
3
4
5
# grep -n '[^g]oo' regular_express.txt
2:apple is my favorite food.
3:Football game is not use feet only.
18:google is the best tools for search keyword.
19:goooooogle yes!

第2,3行没有疑问,因为fooFoo均是符合要求的结果,但是第18行明显有googlegoo,因为该行后面出现了tooltoo所以该行也被列出来;第19行,同样的因为goooooogle里面的oo前面可能是o ,所以这一行也是符合要求。

连续字符的搜索:搜索oo前面不要有小写字母

1
2
# grep -n '[^a-z]oo' regular_express.txt
3:Football game is not use feet only.

如果该字符组是连续的,例如大写英文/小写英文/数字等等, 就可以使用[a-z],[A-Z],[0-9]等方式来书写,例如果我们的要求字串是数字与英文,变成:[a-zA-Z0-9]。

获取有数字的那一行:

1
2
3
# grep -n '[0-9]' regular_express.txt
5:However, this dress is about $ 3183 dollars.
15:You are the best is mean you are the no. 1.

行首与行尾字符:^ $

查找the开头的行:

1
2
# grep -n '^the' regular_express.txt
12:the symbol '*' is represented as start.

查找开头是小写字符的行:

1
# grep -n '^[a-z]' regular_express.txt

查找开头不是英文字母的行:

1
# grep -n '^[^a-zA-Z]' regular_express.txt

注意: ^符号,在字符类符号(括号[])之内与之外是不同的,在[]内代表反向选择,在[]之外代表定位在行首

查找小数点.结尾的行:

1
# grep -n '\.$' regular_express.txt

特别注意:因为小数点在正则表达式中具有其他意义(见后文),所以必须要使用转义字符\

查找空白行:

1
# grep -n '^$' regular_express.txt

因为只有行首跟行尾^$,所以这样可以找出空白行.

任意一个字符.与重复字符*

这两个符号在正则表达式的意义如下:
.(小数点):代表一定有一个任意字符
*(星号):代表重复前一个字符0到无穷多次

找出g??d的字串,即共有四个字符,起头是g而结束是d,我可以这样做:

1
2
3
4
# grep -n 'g..d' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
9:Oh! The soup taste good.
16:The world <Happy> is the same with "glad".

因为强调gd之间一定要存在两个字符,因此第13行的god与第14行的gd就不会被列出来.

如果想要列出有oo,ooo,oooo等等的数据, 也就是说,至少要有两个(含)o以上
因为*代表的是重复0个或多个前面的RE字符的意义, 因此o*代表的是:拥有空字符或一个o以上的字符
因此grep -n 'o*' regular_express.txt将会把所有的数据都打印出来
当我们需要至少两个o以上的字串时,就需要ooo*,即:

1
2
3
4
5
6
7
# grep -n 'ooo*' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
9:Oh! The soup taste good.
18:google is the best tools for search keyword.
19:goooooogle yes!

如果想要查找字符串开头与结尾都是g,但是两个g之间仅能存在至少一个o,即gog,goog,gooog等等:

1
2
3
# grep -n 'goo*g' regular_express.txt
18:google is the best tools for search keyword.
19:goooooogle yes!

如果想要找出g开头与g结尾的行,当中的字符可有可无:

1
2
3
4
5
6
# grep -n 'g.*g' regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
14:The gd software is a library for drafting programs.
18:google is the best tools for search keyword.
19:goooooogle yes!
20:go! go! Let's go.

因为是g开头与g结尾,中间任意字符均可接受,.*的RE表示任意字符是很常见的.

如果想要找出含有任意数字的行:

1
# grep -n '[0-9][0-9]*' regular_express.txt

限定连续RE字符范围{}
我们可以利用.*来配置0个到无限多个重复字符,那如果我想要限制一个范围区间内的重复字符呢?
举例来说,我们想要找出2个到5个o的连续字串,该如实现?
这时候就得要使用到限定范围的字符{}了,但因为{}的符号在shell里有特殊意义的,因此我们必须要使用转义字符\才行.

1
# grep -n 'o\{2,5\}' regular_express.txt

如果我们要找出g后面接2到5o,然后再接一个g的字符串:

1
2
# grep -n 'go\{2,5\}g' regular_express.txt
18:google is the best tools for search keyword.

如果我想要的是2个o以上的goooo....g呢?除了可以是gooo*g,也可以是:

1
[root@www ~]# grep -n 'go\{2,\}g' regular_express.txt

扩展grep(grep -Eegrep)

使用扩展grep的主要好处是增加了额外的正则表达式元字符集

打印所有包含NWEA的行。如果不使用egrep,而是grep,将不会有结果查出:

1
2
3
# egrep 'NW|EA' testfile
northwest NW Charles Main 3.0 .98 3 34
eastern EA TB Savage 4.4 .84 5 20

对于标准grep,如果在扩展元字符前面加\,grep会自动启用扩展选项-E:

1
2
3
#grep 'NW\|EA' testfile
northwest NW Charles Main 3.0 .98 3 34
eastern EA TB Savage 4.4 .84 5 20

搜索所有包含一个或多个3的行:

1
2
3
# egrep '3+' testfile
# grep -E '3+' testfile
# grep '3\+' testfile

搜索所有包含0个或1个小数点字符的行:

1
2
3
4
5
6
7
# egrep '2\.?[0-9]' testfile
# grep -E '2\.?[0-9]' testfile
# grep '2\.\?[0-9]' testfile
#首先含有2字符,其后紧跟着0个或1个点,后面再是0和9之间的数字.
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 2 18
eastern EA TB Savage 4.4 .84 5 20

搜索一个或者多个连续的no的行

1
2
3
4
5
6
7
# egrep '(no)+' testfile
# grep -E '(no)+' testfile
# grep '\(no\)\+' testfile
#3个命令返回相同结果
northwest NW Charles Main 3.0 .98 3 34
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9

不使用正则表达式(fgrepgrep -E)

fgrep查询速度比grep命令快,但是不够灵活:它只能找固定的文本,而不是正则表达式
如果你想在一个文件或者输出中找到包含星号字符的行:

1
2
3
fgrep  '*' /etc/profile

grep -F '*' /etc/profile

0%