首頁 > 軟體

Linux grep 命令詳解

2020-06-16 16:32:42

Grep 是 Global Regular Expression Print 的縮寫,它搜尋指定檔案的內容,匹配指定的模式,預設情況下輸出匹配內容所在的行。注意,grep 只支援匹配而不能替換匹配到的內容。

基本語法

語法格式:
grep [OPTIONS] PATTERN [FILE...]
grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]

grep 支援不同的匹配模式,比如預設的 BRE 模式,增強型的 ERE 模式,還有更強悍的 PRE 模式。普通情況下使用預設的 BRE(basic  regular  expression) 模式就可以了,這種方式的特點是支援的正規表示式語法有限。如果需要更進一步的正規表示式語法支援,可以使用 ERE(extended regular expression) 模式。如果要使用複雜的正規表示式語法,可以使用 PRE 模式,它支援 Perl 語言的正規表示式語法。

常用選項:
--help
-V, --version
-G, --basic-regexp        BRE 模式,也是預設的模式
-E, --extended-regexp  ERE 模式
-P, --perl-regexp          PRE 模式
-F, --fixed-strings          指定的模式被解釋為字串
-i 忽略大小寫
-o 只輸出匹配到的部分(而不是整個行)
-v 反向選擇,即輸出沒有沒有匹配的行
-c 計算找到的符號行的次數
-n 順便輸出行號

常見用例

遞回目錄中的所有檔案
預設情況下 grep 會匹配指定定檔案中的內容,如果我們指定了一個目錄,grep 則直接罷工:

使用選項 -R, -r, --recursive 會遞回指定目錄下的所有檔案,並匹配其內容:

$ grep -r 'world' ~/projects/

通過 -d recurse 選項可以實現同樣的功能:

$ grep 'world' -d recurse ~/projects/

在遞回的過程中只輸出匹配內容所在的檔名稱
如果我們只想檢視匹配到的內容所在檔案的名稱,可以同時使用 r 和 -l, --files-with-matches 選項:

$ grep -rl email /home/nick/projects/bash/.git

在遞回的過程中排除某些目錄
可以在應用選項 r 的同時應用 --exclude-dir 選項來排除一些目錄(注意,這裡設定的也是正規表示式):

$ grep -r --exclude-dir='.git' 'email' .

還可以同時指定多個表示式:

$ grep -r --exclude-dir={.git,xgit} 'email' .

在遞回的過程中排除指定的檔案
可以在應用選項 r 的同時應用 --exclude 選項來排除一些檔案(注意,這裡採用的是 GLOB模式):
$ grep -r --exclude=*.txt 'email' .

不區分大小寫
Grep 預設的匹配規則區分字元的大小寫,使用選項 -i (小寫字母i), --ignore-case 會在匹配中忽略字元大小寫:

$ grep -i 'hello' email1

只輸出匹配到的部分(而不是整個行)
Grep 預設會輸出匹配到的內容所在的整個行,使用選項 -o, --only-matching 則只輸出匹配到的內容:

$ echo "abc 123 test" | grep -o '[0-9]{1,3}'

輸出的結果為:123
在需要把匹配的內容存入變數時 -o 選項非常有用,比如下面的範例把從檔案中匹配到的 IP 地址儲存在變數 ip 中:

ip=$(grep -o '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}' file.log)
if test -z "${ip}"; then
    exit 1
fi
echo ${ip}

把匹配條件當成一個字串
有時候我們想要匹配一個固定的字串,但是其中包含了特殊字元,比如:

$ grep '.*' email1.txt 

這樣的條件會返回檔案中的每一行內容,這不是我們想要的。可以通過跳脫符來解決這個問題:

$ grep '.*' email1.txt

當然,我們還可以通過選項 F 來優美的解決這個問題,此時指定的條件會被當成一個字串來匹配:

$ grep -F '.*' email1.txt

同時輸出匹配行後的 n 行
使用選項 -A n 可以輸出匹配行後的 n 行,結合 ps 命令,可以用來查詢某個進程的子進程。下面的例子通過 -A 1 輸出容器執行的進程(bash):

$ ps fxa | grep -A 1 docker

同時輸出匹配行前後的行
有時我們想要看到匹配行的前後行的內容,使用選項 -C n 可以實現這個功能,比如下面的命令會同時輸出匹配行前後 1 行的內容:

$ grep -C 1 'grey' email1.txt

在輸出中顯示行號
使用選 -n 可以在輸出中顯示行號:

統計匹配到的行的數量
使用選項 -c 可以統計匹配到的行的數量:

反轉匹配條件
如果我們想要獲取正規表示式沒有匹配到的行,可以使用選項 -v, --invert-match

$ grep -v '^[a-zA-Z].*' email1.txt

上面的輸出為不是以字母開頭的行。

只匹配完整的行
如果我們只對一個完整的行感興趣,可以使用選項 -x, --line-regexp。這樣會忽略那些包含在行中的內容:

從檔案中讀取正規表示式
如果正規表示式太長,或者是需要指定多個正規表示式,可以把它們放在檔案中,然後使用 選項 -f FILE, --file=FILE 來指定這個檔案。如果指定了多個正規表示式(每行一個),任何一個匹配到的結果都會被輸出:

使用預定義的命名字元類

$ grep '[[:digit:]]{1,3}' email1.txt

BRE(basic  regular  expression)

語法 說明 解釋
. 匹配一個任意的字元 在 [] 中 . 號並不是元字元
^ 行的起始 ^ 和 $ 匹配的是一個位置而不是具體的文字
$ 行的結束 ^ 和 $ 匹配的是一個位置而不是具體的文字
* 匹配 0 次或多次 不匹配上一次表示式,匹配上一次或匹配多次,並生成所有可能的匹配
匹配儘可能多的次數,如果實在無法匹配,也不要緊
[] 匹配若干個字元之一 又叫字元組、字元類,比如 [0-9]、[a-z]、[A-Z]
只有在字元組內部 - 才是元字元,表示一個範圍
[^...] 排除型字元組 字元組以 ^ 開頭,它會匹配一個任何未列出的字元
? 可選元素 在 BRE 中需要使用跳脫符
出現一次或者不出現
+ 匹配 1 次或多次 在 BRE 中需要使用跳脫符
匹配前面表示式的至少一個搜尋項
匹配儘可能多的次數,如果實在無法匹配,也不要緊
 {min,max}  量詞區間 在 BRE 中需要使用跳脫符
 |  或(多選結構) 在 BRE 中需要使用跳脫符
bob|nick 能夠同時匹配其中任意一個的正規表示式,此時的子表示式被稱為 "多選分支"
多選結構可以包括很多字元,但不能超越括號的界限
 ()  分組 在 BRE 中需要使用跳脫符
括號能夠 "記住" 它們包含的子表示式匹配的文字
反向參照(backreference)是正規表示式的特性之一,它允許我們匹配與表示式先前部分匹配的同樣的文字
 <>  單詞分界符 在 BRE 中需要使用跳脫符
< 和 > 本身並不是源字元,只有它們與反斜線結合時才具有單詞分界符的含義
   跳脫符 如果需要匹配的某個字元本身就是元字元,就需要使用跳脫符
  命名的字元類  命名的預定義字元類 [[:upper:]]  [A-Z]
[[:lower:]]  [a-z]
[[:digit:]]  [0-9]
[[:alnum:]]  [0-9a-zA-Z]
[[:space:]]  空格或 tab
[[:alpha:]]  [a-zA-Z]

ERE(extended regular expression)

與 BRE 相比 ERE 最大的優點是支援更多的元字元,也就是在使用這些字元時不需要 了。比如上面 BRE 中使用的 符可以全部去掉。


IT145.com E-mail:sddin#qq.com