linux下的grep可以对文件进行过滤,并返回匹配到的行,但有时我们只需要匹配行中的部分内容,而不是整行,一般都是用awk等对匹配行进行二次切分等。本文介绍一种用grep正则匹配模式只返回所需部分的内容,包括一行数据里匹配到多个结果。
目录导航
参数
-o, --only-matching show only the part of a line matching PATTERN
-o参数只返回匹配PATTERN的部分
-P, --perl-regexp
Interpret PATTERN as a Perl regular expression. This is highly experimental and grep -P may warn of unimplemented features.
-P参数使用perl样式的正则表达式。
注意:查看man文档,perl正则部分还处于实验阶段,所以... 用还是不用自己决定。
正则表达式 Pattern
零宽,表示并不算匹配结果,但参与匹配的过程。
(?<=) 零宽度正预测先行断言
它断言自身出现的位置的后面能匹配表达式exp
(?<=exp)零宽度正回顾后发断言
它断言自身出现的位置的前面能匹配表达式exp
(.+?)匹配内容
参考Perl正则规则,其中
- 点(.)表示任意字符
- + 表示最少1个字符,不允许空
- * 表示任意数量字符,可以为空
- ?表示尽量少的匹配,比如一行可能有多次命中,如果不加,会造成第一个先行断言和最后一个后行断言之间整体返回,后面有例子
样例
如下以获得IP地址为例
默认匹配返回整行
无论是-E还是-P 都是返回整个匹配的行
[root@rh6-1 log]# echo "121212<IpAddress>10.0.2.201</IpAddress>343456"|grep -E '<IpAddress>.+?</IpAddress>'
121212<IpAddress>10.0.2.201</IpAddress>343456
[root@rh6-1 log]# echo "121212<IpAddress>10.0.2.201</IpAddress>343456"|grep -P '<IpAddress>.+?</IpAddress>'
121212<IpAddress>10.0.2.201</IpAddress>343456
一行一个匹配结果
此处的匹配Pattern为
'(?<=<IpAddress>)(.+?)(?=</IpAddress>)
表示匹配位置前面有<IpAddress>,匹配位置右面有</IpAddress>, 返回的是匹配到的10.0.2.201的IP
[root@rh6-1 log]# echo "121212<IpAddress>10.0.2.201</IpAddress>343456"|grep -oP '(?<=<IpAddress>)(.+?)(?=</IpAddress>)'
10.0.2.201
[root@rh6-1 log]#
一行多个匹配结果
可以看到,一行数据匹配到了2个位置,结果集也是2行。
[root@rh6-1 log]# echo "121212<IpAddress>10.0.2.201</IpAddress>342<IpAddress>10.0.2.202</IpAddress>3456"|grep -oP '(?<=<IpAddress>)(.+?)(?=</IpAddress>)'
10.0.2.201
10.0.2.202
其中的匹配位置包括了? 最短匹配,如果没有,返回结果如下
[root@rh6-1 log]# echo "121212<IpAddress>10.0.2.201</IpAddress>342<IpAddress>10.0.2.202</IpAddress>3456"|grep -oP '(?<=<IpAddress>)(.+)(?=</IpAddress>)'
10.0.2.201</IpAddress>342<IpAddress>10.0.2.202
这个包含了2个IP以及之间其它字符的结果,肯定不是预期的结果。