Linux檔案處理三劍客之grep

joshliu發表於2023-11-27

背景

    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”的使用者資訊

grep nologin /etc/passwd

    

    *注:grep只是將包括"nologin"關鍵字的整行給輸出來,而不考慮"nologin"在該行的位置。也就是說,如果有一個使用者叫做"nologin1"但是它又是可以login的,那透過上述grep命令,同樣也能獲取到該行(而這並非一個有效的行)

    所以,如果要準確查詢出系統下“nologin”的使用者資訊,需要保證"nologin"出現在行尾,對上述命令進行改進後:

grep 'nologin$' /etc/passwd

    *注:grep搜尋時,^表示開頭,$表示結尾


  •     搜尋出當前資料夾下有哪些子資料夾

ls -l | grep ^d

    

    

  •     搜尋出系統中ifconfig配置的ip資訊

ifconfig | grep -w inet

    

    *注:如果使用了-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 'Accepted password for root from' 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。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69985104/viewspace-2995082/,如需轉載,請註明出處,否則將追究法律責任。

相關文章