2021-05-12 14:32:11
Linux grep 命令詳解
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 中使用的 符可以全部去掉。
相關文章