背景
grep命令最初是由美國計算機科學家肯·湯普遜(Ken Thompson)在1974年發明, 為了讓用戶全局搜索所有匹配的內容并打印它們,所以使用 g/regularexpression/p, 簡單地寫成 g/re/p( globally search a regular expression and print)。后來也可以解釋為"Global Regular Expression Print"(全局正則表達式打印)的首字母縮寫。
肯·湯普遜發明grep命令的主要動機是為了提供一種強大而靈活的文本搜索工具,以滿足Unix操作系統用戶處理文本數據的需求。在當時,Unix系統的用戶需要一種能夠快速搜索文本文件中特定模式的工具,以便在處理文本數據時能夠高效地定位和提取所需的信息。肯·湯普遜意識到,為了提高Unix系統的實用性,需要一種能夠靈活處理文本數據的工具,而grep命令的發明正是為了滿足這一需求。
格式
grep命令格式較為簡單,grep [OPTIONS] PATTERN [FILE/FOLD...],其中 :
-
OPTIONS為選項
-
PATTERN 為搜索模式
-
FILE 為文件名;如果使用-r遞歸搜索的時候,可以選擇某個文件夾( FOLD)
* 注:如果省略 FILE/FOLD,則從標準輸入讀取內容
參數
本文僅介紹常用參數,如果讀者有興趣了解更多參數,請運行“man grep”或者“grep --help”查看。
-
-i:ignore 忽略大小寫
-
-c:count 取行數
-
-w: word 匹配單詞
-
-E:extended 正則
-
-P:perl 正則
-
-l:list 列出包含關鍵字的文件
-
-A:after 取出匹配行以及后續行
-
-B:before 取出匹配行以及前續行
-
-C:取出匹配行的上下行
-
-R:在目錄下搜索,比如grep 'abc' ./,表示在當前目錄下所有文件進行查找
-
-v:invert 排除
-
-n:number 顯示行號
-
-o:only matching 只顯示匹配到的內容
-
-r:recursive 遞歸式搜索
grep的參數是比較多并且復雜的,但無論如何,grep命令的本質還是在于“文件內容的搜索”,而不是“文件名的搜索”。
返回值
-
0 :表示成功
-
1 :表示所提供的文件無法找到匹配的pattern
-
2 :表示查找地點不對
實戰
-
搜索出當前系統下“nologin”的用戶信息
grepnologin/etc/passwd
*注:grep只是將包括"nologin"關鍵字的整行給輸出來,而不考慮"nologin"在該行的位置。也就是說,如果有一個用戶叫做"nologin1"但是它又是可以login的,那通過上述grep命令,同樣也能獲取到該行(而這并非一個有效的行)
所以,如果要準確查詢出系統下“nologin”的用戶信息,需要保證"nologin"出現在行尾,對上述命令進行改進后:
grep'nologin$'/etc/passwd
*注:grep搜索時,^表示開頭,$表示結尾
-
搜索出當前文件夾下有哪些子文件夾
ls-l|grep^d
-
搜索出系統中ifconfig配置的ip信息
ifconfig|grep-winet
*注:如果使用了-w選項,那有單獨inet關鍵字的行會被搜索出來,但是inetabc的行,不會被匹配
同樣,如果為了更精確搜索配置的ip信息,應該以每行開頭為“多個空格加inet”這樣的形式進行檢索,命令如下:
ifconfig|grep'^[]*inet'
*注:上述命令中,[ ]代表一個空格字符,*表示重復前面0個或者多個;如果[abc]*,表示“
任意abc字符中的一個”重復0次或者多次,所以[abc]*既可以匹配a或者b或者c,也可以匹配abc或者aaa或者abcabc,同樣也能匹配aabccc
-
搜索出系統中ifconfig配置的ip信息,以及對應的網卡名稱
為了檢索出上述內容,用戶需要首先了解ifconfig輸出的信息:在正常ifconfig的輸出中,inet上一行的內容,即是對應的網卡名稱。
ifconfig|grep-B1'^[]*inet'
*
注:如果-B2,代表將匹配行上面2行同時打印出來
-
檢索出/proc/cpuinfo中,關鍵字“processor”在文件中的行號
grep-n'processor'/proc/cpuinfo
*注:上述輸出結果中,左右綠色部分,即為關鍵字在源文件中的行號
同樣,如果需要統計關鍵字“processor”在文件/proc/cpuinfo中一共出現了多少次,可以運行如下命令統計:
grep-c'processor'/proc/cpuinfo
*注:如上命令為統計x86系統中處理器的個數
-
在/proc/cpuinfo中檢索出包含關鍵字“processor”往下5行的內容,但需要排除掉有關鍵字“model”的行
首先,通過-A5可以搜索出關鍵字往下5行信息,grep -A5 'processor' /proc/cpuinfo
如果需要再排除掉含有關鍵字“model”的行,通過管道進行二次搜索即可:
grep-A5'processor'/proc/cpuinfo|grep-v'model'
-
在/var/log下,針對所有messages的log,搜索出包含關鍵字fail的文件(忽略fail的大小寫)
grep -i -l 'fail' /var/log/messages*
*注:如果需要在多個文件中搜索,可以grep 'xxx' file1 file2,或者grep 'xxx' file*,或者grep 'xxx' *file
-
在/var/log下,針對所有messages的log,搜索出包含關鍵字fail或者error的內容(忽略大小寫)
grep-i-E'fail|error'/var/log/messages*
*注:-E代表擴展正則,通常情況下有如下5種擴展:
-
+:重復1次或者多次前面的字符,比如grep -E 'ab+c' file,表示在file中搜索包括1個a,多個b,并且跟上1個c的內容
-
?:重復0次或者1次前面的字符,比如grep -E 'ab?c' file, 表示在file中搜索包括1個a,0個b或者1個b,并且跟上1個c的內容
-
|:用“或”的方式查找多個符合的字符串,比如grep -E 'fail|error' file
-
():作為某個特定組合,比如說grep -E 'level=(fail|error)' file,表示在file中查找包括level=fail或者level=error的內容。如果去掉括號grep -E 'level=fail|error' file,代表查找匹配level=fail或者一行中單獨匹配error的內容
-
{m,n}/{m,}/{,n}/{n}:表示重復m到n次(閉區間)/大于等于m次/小于等于n次/n次,在不用-E參數時,所有這部分花括號用法得兩側加反斜線:\{m,n\}
-
在/var/log/secure*文件中,統計出最近通過ssh訪問本服務器的ip以及端口信息
首先,如果簡單查看/var/log/secure文件,可以發現根據關鍵字"Accepted password for root from"可以獲取到粗略信息如下:
但如果只是想獲取到訪問本服務器的ip以及端口信息(ip與端口不相同),此時就需要進行正則匹配,同時將匹配的內容給輸出來,而不顯示行中其它信息:
grep'Acceptedpasswordforrootfrom'secure*|grep-o'[0-9\.]*port[0-9]*'
*注:-o是僅僅將匹配的內容顯示出來(而不顯示整行)。通過-o加正則的方式,可以獲取出被grep匹配到的內容。
-
在當前文件夾以及子文件夾下搜索內容包括'error'的信息
有時候系統會將過期日志新建一個子文件夾,并remove到該文件夾下去,如果某天用戶希望找到當前文件夾以及子文件夾下的文件內容包括'error'的相關信息,可以通過-r參數來實現:
grep-r'error'./
*注:如果執行grep -r 'error' ./*.log,僅僅代表在當前目錄下*.log文件中搜索'error'關鍵字的行
-
取出Oracle的ddl中,普通索引或者unique索引的列名中包括'#'的相關行?(假設索引定義都在一行)
首先,Oracle的ddl信息如下:
嘗試一:grep -E 'CREATE INDEX|CREATE UNIQUE INDEX' ora_ddl.sql | grep '#'
分析,該嘗試可能存在問題,如果索引名帶'#',也會搜索出來
嘗試二:grep 'CREATE INDEX|CREATE UNIQUE INDEX' ora_ddl.sql -E | grep -P ‘\(.+?\#.+?\)’
分析,上述語句首先將索引或者unique索引行搜索出,再通過-P的perl正則,對索引定義的括號"()"內字段名進行匹配,從而準確匹配出索引列中包括'#'的內容
嘗試三:grep -P 'CREATE\s+(UNIQUE\s+){0,1}INDEX.+?\(.+?\#.*?\)' ora_ddl.sql
分析,上述語句通過一次grep,直接準確匹配出索引或者unique索引字段中包括'#'的內容
*注:perl正則匹配中
-
. 代表任意字符
-
\s代表空格或者制表符
-
()中內容代表某個整體
-
+代表匹配一次或者多次
-
*代表匹配0次或者多次
-
.+?代表匹配到最近的對象(非貪婪)
-
{1,5}代表匹配1-5次(非1次跟5次,而是1次,2次,3次…5次)
總結
grep命令用來在文件中搜索匹配的內容,既可以在當前文件夾搜索,也可以在當前文件夾以及子文件夾搜索。既可以搜索一個文件,也可以搜索多個文件。grep提供了多種搜索的方式,既可以忽略大小寫,也可以全詞檢索,還可以使用普通正則或者擴展正則再或者perl的正則。并且在輸出結果的時候,既可以輸出匹配的內容/文件名,也可以輸出對應的行號或者匹配內容的總個數,還可以輸出匹配內容的前后多少行,或者干脆輸出不匹配的部分。在使用正則進行匹配的時候,常見的shell正則grep都能支持,如果有進一步的正則擴展,請使用-E參數。但請注意grep沒辦法對某一列的內容進行匹配而后輸出,除非使用一個很長的正則一直匹配到該列內容。所以很多時候grep的搜索會有不精確性,需要用戶在搜索的基礎上進行二次過濾,或者使用更加準確的搜索pattern。
總之,grep是Linux上強大的文件檢索工具,用戶幾乎可以使用grep一個命令檢索到所需要的各種信息,當然,很多時候還需要使用管道進行多重grep。