grep
grep: Global search REgular expression and Print out the line
作用:文本搜索工具,根据用户指定的“模式”对目标文 本逐行进行匹配检查;打印匹配到的行
模式:由正则表达式字符及文本字符所编写的过滤条件
grep [OPTIONS] PATTERN [FILE...]
grep root /etc/passwd
grep "$USER" /etc/passwd
grep '$USER' /etc/passwd
grep `whoami` /etc/passwd
grep命令选项
--color=auto: 对匹配到的文本着色显示
-v: 显示不被pattern匹配到的行
-i: 忽略字符大小写
-n:显示匹配的行号
# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
-c: 统计匹配的行数
# grep -c root /etc/passwd
2
-o: 仅显示匹配到的字符串
grep -o root /etc/passwd
root
root
root
root
-q: 静默模式,不输出任何信息 主要在脚本中使用,之查看匹配结果是否成功,并不关注匹配的结果
# grep -q root /etc/passwd
# echo $?
0
# grep -q root11 /etc/passwd
# echo $?
1
-A #: after, 后#行
# grep -nA3 root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
2-bin:x:1:1:bin:/bin:/sbin/nologin
3-daemon:x:2:2:daemon:/sbin:/sbin/nologin
4-adm:x:3:4:adm:/var/adm:/sbin/nologin
--
10:operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12-ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13-nobody:x:99:99:Nobody:/:/sbin/nologin
-B #: before, 前#行
# grep -nB3 root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
--
7-shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8-halt:x:7:0:halt:/sbin:/sbin/halt
9-mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
-C #:context, 前后各#行
# grep -nC3 root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
2-bin:x:1:1:bin:/bin:/sbin/nologin
3-daemon:x:2:2:daemon:/sbin:/sbin/nologin
4-adm:x:3:4:adm:/var/adm:/sbin/nologin
--
7-shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8-halt:x:7:0:halt:/sbin:/sbin/halt
9-mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10:operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12-ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13-nobody:x:99:99:Nobody:/:/sbin/nologin
-e:实现多个选项间的逻辑or关系
# grep -e root -e haha /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
haha:x:1011:1011::/home/haha:/bin/bash
-w:整行匹配整个单词
-E:使用ERE
-F:相当于fgrep,不支持正则表达式
正则表达式
REGEXP:由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能
程序支持:grep, vim, less,nginx等
分两类:
基本正则表达式:BRE
扩展正则表达式:ERE
grep -E, egrep
正则表达式引擎:
采用不同算法,检查处理正则表达式的软件模块
PCRE(Perl Compatible Regular Expressions)
元字符分类:字符匹配、匹配次数、位置锚定、分组
man 7 regex
字符匹配:
.匹配任意单个字符
[] 匹配指定范围内的任意单个字符
[^] 匹配指定范围外的任意单个字符
[:alnum:] 字母和数字
[:alpha:] 代表任何英文大小写字符,亦即A-Z, a-z
[:lower:] 小写字母[:upper:] 大写字母
[:blank:] 空白字符(空格和制表符)
[:space:]水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
匹配次数:用在要指定次数的字符后面,用于指定前面的字符要出现的次数
* 匹配前面的字符任意次,包括0次
贪婪模式:尽可能长的匹配
.*任意长度的任意字符
?匹配其前面的字符0或1次
+匹配其前面的字符至少1次
{n}匹配前面的字符n次
{m,n}匹配前面的字符至少m次,至多n次
{,n}匹配前面的字符至多n次
{n,}匹配前面的字符至少n次
位置锚定:定位出现的位置
^ 行首锚定,用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^PATTERN$ 用于模式匹配整行
^$ 空行
^[[:space:]]*$ 空白行
< 或词首锚定,用于单词模式的左侧
> 或词尾锚定;用于单词模式的右侧
<PATTERN>匹配整个单词
分组:() 将一个或多个字符捆绑在一起,当作一个整体进行处理,如:(root)+
分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: 1, 2, 3, ...
1表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
示例:(string1+(string2)*)
1 :string1+(string2)*
2 :string2
后向引用:引用前面的分组括号中的模式所匹配字符,而非模式本身
egrep及扩展的正则表达式
egrep= grep -E
egrep[OPTIONS] PATTERN [FILE...]
字符匹配:
. 任意单个字符
[] 指定范围的字符
[^] 不在指定范围的字符
次数匹配:
*:匹配前面字符任意次
?: 0或1次
+:1次或多次
{m}:匹配m次
{m,n}:至少m,至多n次
位置锚定:
^ :行首
$ :行尾
<, :词首
>, :词尾
分组:
()
后向引用:1, 2, ...
或者:
a|b: a或b
C|cat: C或cat
(C|c)at:Cat或cat
上面主要介绍正则的字符匹配,次数匹配,位置锚定,分组,或者等语法等。
下面主要介绍一个我在学习正则时的例子,以这个具体事例分析为主来剖析。
例子:
使用正则取出/etc/passwd文件中系统用户。(centos7系统用户是UID等于0-999)
分析题目需求,寻找解决方案,正则思路其实很多,每个人想出方法可能会各有不同,但是结果达就是成功。
这里我提供下这道题我的思路:
1.首先我们取出/etc/passwd文件中一行来看一看
root:x:0:0:root:/root:/bin/bash
用户名:密码占位符:UID:GID:用户完整信息:主目录:默认shell版本
2.根据题目要求是要求我们取出系统用户名,centos7里面系统用户的UID是0-999,从上面两条要求分析,从文件中我们最少需要先取出用户名(冒号分割第一段)和UID第三段。那么我们接下来目的就是取出文件中第一段和第三段内容,这里我们可以使用cut命令来取。
# cut -d: -f1,3 /etc/passwd #关于cut命令说明请man cut
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-bus-proxy:999
systemd-network:192
dbus:81
polkitd:998
abrt:173
unbound:997
usbmuxd:113
tss:59
libstoragemgmt:996
rpc:32
colord:995
amandabackup:33
saslauth:994
geoclue:993
setroubleshoot:992
rtkit:172
qemu:107
radvd:75
chrony:991
ntp:38
sssd:990
rpcuser:29
nfsnobody:65534
pulse:171
gdm:42
gnome-initial-setup:989
avahi:70
postfix:89
sshd:74
tcpdump:72
xiangge:1000
yongge:1001
newxiangge:1010
haha:1011
hehe:1012
3.继续往下分析我们题目要求是取UID 0-999的用户,那么我们现在需要做的就是从我们第一次取出的结果里面在把包含数字小于999的行取出来就行了。
怎么取?我们大概来分析0-999这些数字特点:1-3位数字组成,出现在每行的行尾,并且为最后一个单词。
大概思路:先字符匹配----》再做次数匹配------》最后做位置锚定
1.)字符匹配
首先把我需要匹配内容的组成字符匹配出来,这个例子我们是需要取内容只包含数字,那么我们匹配出数字就好,根据上面字符介绍我们大概知道匹配数字方式有两种第一种[0-9]或者[:digit:],选择一种自己喜欢的使用就好。
2.)次数匹配
匹配完字符我们接着就是需要匹配我们组成部分里面每种字符出现次数,在相应字符后面加上次数匹配就好,这个例子里面数字出现次数是1-3次那么我们在我们相应的字符后面加上我们次数匹配1-3.
3.)位置锚定
字符和次数匹配完后,我们需要做的就是位置锚定了,从上面结果分析我们需要取出0-999数,这些数是出现在我们需要匹配文本那些位置?
nobody:99
systemd-bus-proxy:999
从上面两个例子可以得出我们需要取出数字是出现在每行的行尾那么行尾需要锚定,但是如果仅仅只是做一个行尾锚定就行?我们看下执行结果再来分析下
# cut -d: -f1,3 /etc/passwd|grep "[0-9]{1,3}$"
但是结果中却出现下面这种情况,明显就是我们范围大了想办法缩小的取范围,我们目标是取出1-3位数字组成的单词并且这个单词必须行尾,像65534一个完整的单词是65534,但是我们需要去的结果534只是出现在这个单词中间某段,明显不符合我们取目标是一个完整单词,这明显不是我们想要的结果,那么怎么才能达到我们的要求?
nfsnobody:65534
xiangge:1000
yongge:1001
newxiangge:1010
haha:1011
hehe:1012
解决上面方法就是我们把词首锚定下,问题就解决了
# cut -d: -f1,3 /etc/passwd|grep "[0-9]{1,3}$"
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-bus-proxy:999
systemd-network:192
dbus:81
polkitd:998
abrt:173
unbound:997
usbmuxd:113
tss:59
libstoragemgmt:996
rpc:32
colord:995
amandabackup:33
saslauth:994
geoclue:993
setroubleshoot:992
rtkit:172
qemu:107
radvd:75
chrony:991
ntp:38
sssd:990
rpcuser:29
pulse:171
gdm:42
gnome-initial-setup:989
avahi:70
postfix:89
sshd:74
tcpdump:72
上面如果你不想使用词首锚定,也可以使用grep -w 匹配单词,也能达到我们想要的结果。
# cut -d: -f1,3 /etc/passwd|grep -w "[0-9]{1,3}$"
以上为我处理这个题目的思路,可以尝试使用我推荐这个思路去练习,我个人感觉这个方法可以很清晰的分析出我们一般的正则基本规则,从而匹配出我们想要的结果。
最后可以尝试使用上面思路去过滤出ifconfig命令查看的结果中所有的IP地址。
下面提供一个我个人答案,可以按这个思路去思考下。
# ifconfig|egrep -o "([0-9]+.){3}[0-9]{1,3}"
192.168.31.32
255.255.255.0
192.168.31.255
192.168.199.156
255.255.255.0
192.168.199.255
127.0.0.1
255.0.0.0
192.168.122.1
255.255.255.0
192.168.122.255