先說問題,統計一個日志文件中去重之后的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地址 等等。
正則表達式實際中用途很廣,有興趣的可以點擊 正則表達式 查看更詳細的教程