先说问题,统计一个日志文件中去重之后的ip地址的个数。其实这是一个非常常见也比较简单的问题,其中我个人认为最主要的应该是匹配ip地址是这个问题的核心。剩下的就是对linux命令的熟练程度的问题了。
首先这里我说一下我解决这个问题用到的命令是
下面我们主要介绍grep
如何匹配出ip地址
grep
作为linux中使用频率非常高的一个命令,和cut命令一样都是管道命令中的一员。并且其功能也是对一行数据进行分析,从分析的数据中取出我们想要的数据。也就是相当于一个检索的功能。当然了,grep的功能要比cut强大的多了。grep检索的条件是多种多样的,甚至还可以和正则表达式合作来检索。这里我们主要就是用它的正则表达式。
其中我们主要用到grep的下面几个选项
-
-i
不区分大小写匹配; -
-o
只显示匹配的字符串 -
-E
指定正则表达式
对于Ip地址,取值范围为 0.0.0.0-255.255.255.255。所以说我们可以先匹配 0-255,然后将该正则表达式重复四次即可。
下面先看一下匹配0-255的正则表达式。
(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))
这里我们分解一下这个正则表达式,首先对于第一位可能是2的情况:200-255
。所以可以用正则表达式:2[0-5]{2}
。然后是匹配 100-199
的情况,那第一位肯定就是判断是否为1了。但是到了这里就要分情况来讨论了一下了,如果是三位的,那就是100-199
;如果是两位的话,那就是匹配10-99
,如果是一位的话,那就是匹配0-9
。所以这里对于第一位1可以是可选择的,然后后面将1是否存在作为条件来判断是否是匹配100-199。所以我们还需要一个条件子组
下面我们看一下正则表达式
((1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))
如果1被捕获,那条件(?(\2)
为真,那么后面就跟着是[0-9]{2}
;否则(?(\2)
为假,就走else-pattern
,用一个可选路径([1-9][0-9]|[0-9])
就可以匹配10-99
或者0-9
。
所以综合起来就是
(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))
然后再在前面加上点并重复3次
(\.(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))){3}
最后连起来整个正则表达式就是
(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))(\.(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))){3}
通过grep
加上面的正则表达式匹配出所有的ip地址;然后通过uniq
命令进行去重;最后再用wc
进行统计。整个命令如下
$ grep -ioE '(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))(\.(2[0-5]{2}|(1)?(?(\2)[0-9]{2}|([1-9][0-9]|[0-9])))){3}' | uniq -c | wc -l
上面这个问题只是grep利用正则表达式的一个应用。也可以有很多的变形问题,比如统计IP地址访问次数之后进行一个排序,找出访问次数前十的ip地址 等等。
正则表达式实际中用途很广,有兴趣的可以点击 正则表达式