作者:守望,Linux應用開發者,目前在公眾號【程式設計珠璣】 分享Linux/C/C++/資料結構與演演算法/工具等原創技術文章和學習資源。
前言
之前介紹過很多linux下查詢相關的命令,例如《Linux中的檔案查詢技巧》,《find命令高階用法》,《如何檢視linux中檔案開啟情況》等等,而對檔案內容搜尋的命令似乎還沒有涉及,因此本文介紹文字搜尋命令–grep。
常見用法
我們會經常結合管道符(|)來使用它,即在前面命令執行的結果中查詢包含相關字串的內容。例如:
$ ps -ef|grep redis
ps -ef用於檢視系統行程情況,但是它列出的結果很多,如果我們只想看到自己需要的,則透過管道符,用grep進行過濾搜尋,例如搜尋redis相關的行程,最後它只會列出和redis相關的行程了:
$ ps -ef|grep redis
root 10748 10733 0 21:14 pts/21 00:00:00 redis-server *:6379
root 10754 10733 0 21:14 pts/21 00:00:00 grep --color=auto redis
那麼如果要排除某些不相關資訊呢?我們可以使用-v引數
$ ps -ef|grep redis |grep -v auto
root 10748 10733 0 21:14 pts/21 00:00:00 redis-server *:6379
這樣一來,包含auto相關的結果就不會出現在最終結果裡了。
如果只想統計結果數量呢?我們可以結合-c(count)引數:
$ ps -ef|grep redis -c
2
檔案內容搜尋
好了,說完了最常見的用法,我們來看看如何搜尋檔案內容。實際上awk和sed在這方面也頗有經驗,不過本文的主角是grep,所以另外兩個命令暫時不涉及。我們來看幾個實體。
在指定檔案中查詢指定關鍵字
例如,要在linux_command_debug.md檔案中,查詢test字串:
$ grep "test" aaa/bbb/linux_command_debug.md
int test(int a,int b)
test(a,b);
如果想要顯示指定關鍵字的行號,可以使用-n引數,例如:
$ grep -n "test" aaa/bbb/linux_command_debug.md
18:int test(int a,int b)
27: test(a,b);
搜尋時指定或排除多個檔案
前面提到了對一個檔案內容進行搜尋,如果是多個呢?或者不想從某些檔案裡搜尋呢?
如果想對檔案進行指定也是可以的,例如搜尋所有的md結尾的檔案:
$ grep -n "test" *.md
或者可以使用–exclude引數來排除某些檔案,例如,查詢包含test,但是排除txt檔案:
$ grep -rn "test" --exclude=*.txt
搜尋時就會忽略.txt結尾的檔案了。
如果要排除的條件比較多,可以將要排除的條件儲存在另外一個檔案裡:
$ grep -rn "test" --exclude-from=skip.txt
skip.txt的內容可以是樣式匹配的檔案名或者具體檔案名:
*.txt
test.md
這樣,以.txt結尾,以及test.md檔案都不會搜尋了。
除此之外,還可以排除指定目錄,它需要用到–exclude-dir引數:
$ grep -rn "test" --exclude-dir=aaa
它在搜尋時將會跳過aaa目錄下的檔案。
查詢包含指定關鍵字的檔案
如果要在當前目錄下所有檔案查詢包含“int main(void)”字串的檔案:
$ grep -rn "int main(void)"
aaa/bbb/c_main_func.md:49:int main(void)
aaa/bbb/c_main_func.md:71:int main(void) { /* ... */ }
aaa/bbb/c_array.md:104:int main(void)
aaa/bbb/c_array.md:129:int main(void)
aaa/bbb/pc-lint.md:42:int main(void)
aaa/bbb/pc-lint.md:128:int main(void)
這可能是最實用的使用方法之一了。這裡-r引數表示遞迴查詢當前目錄的檔案,-n會顯示查詢位置的行號,如果只想顯示包含該指定關鍵字的檔案名,可使用-l(–file-with-matches)引數:
$ grep -rln "int main(void)"
aaa/bbb/c_main_func.md
aaa/bbb/c_array.md
aaa/bbb/pc-lint.md
如果你嘗試一下就會發現,如果不帶-r引數,它會暫停,等待你從控制檯輸入,例如:
$ grep -n "test"
test
1:test
所以使用時記得帶上相關引數奧!
查詢不包含指定關鍵字的檔案
前面提到瞭如何查詢包含某個關鍵字的檔案,如果要找的是不包含該關鍵字的檔案呢?
實際上只要使用-L引數即可:
$ grep -rLn "int main(void)"
(這裡會顯示不包含指定關鍵字內容的檔案名)
搜尋時忽略大小寫
使用-i(–ignore-case)引數即可:
$ grep -rni "int MAIN(void)"
aaa/bbb/c_main_func.md:49:int main(void)
aaa/bbb/c_main_func.md:71:int main(void) { /* ... */ }
aaa/bbb/c_array.md:104:int main(void)
aaa/bbb/c_array.md:129:int main(void)
aaa/bbb/pc-lint.md:42:int main(void)
aaa/bbb/pc-lint.md:128:int main(void)
搜尋顯示不包含指定關鍵字的行
前面的大部分例子都是顯示符合條件的行,如果要顯示不符合條件的行呢?可以用我們前面提到的-v引數:
$ grep -rnv "int main(void)"
(內容較多,未顯示)
從結果中就會發現,它會展示出包含指定關鍵字的檔案,但是展示的是不包含該關鍵字的行。
顯示指定關鍵字前後內容
假如你需要檢視包含指定關鍵字行附近的行,前面的方式是沒有辦法看到的,不過我們可以用-A(–after-context=)和-B(–before-context=)引數來顯示前後的行:
$ grep -rn "int main(void)" -A 1 -B 1
aaa/bbb/c_array.md-103-}
aaa/bbb/c_array.md:104:int main(void)
aaa/bbb/c_array.md-105-{
(其他內容省略)
透過最後加上-A和-B引數,顯示了指定關鍵字前後的行,這在日誌搜尋分析時非常有用。
指定規則檔案進行搜尋
如果有多個搜尋關鍵字怎麼處理呢?我們可以把關鍵字寫在一個檔案,搜尋時指定檔案即可,例如規則檔案為key.txt:
int main(void)
test
從指定檔案中搜索上面的關鍵字:
$ cat filename |grep -f key.txt
這樣結果就會顯示匹配key.txt檔案中所有關鍵字的行,非常適合用於多個條件的搜尋。
正則運算式搜尋
看完前面的內容,是不是還沒有感受到grep的強大?grep的另一個強大之處是,它的搜尋支援正則運算式,例如查詢文字行以t開頭,以t結尾的檔案:
$ grep -rn ^t.*t$
key.txt:2:test
aaa/bbb/c_operate_redis_start.md:68:typedef struct Stu_Info_Struct
aaa/bbb/c_operate_redis_start.md:101:typedef struct Stu_Info_Struct
其中^t,表明以t開頭,t$表明以t結尾,如果需要使用擴充套件的正則運算式進行搜尋,可使用egrep命令。關於正則運算式的寫法,本文不做詳細介紹。
總結
在內容搜尋方面,grep常常能夠助我們一臂之力,因此掌握grep的使用也是linux學習不可缺少的一部分,當然我們不需要完全記住每個引數的作用,但我們至少知道有這樣的引數,並且在需要時能夠快速查詢到。本文常用引數如下:
-
-v #顯示不包含匹配關鍵字的所有行。
-
-l #顯示包含匹配關鍵字的檔案
-
-L #顯示不包含匹配關鍵字的檔案
-
-r #遞迴搜尋
-
-i #忽略大小寫
-
-n #顯示關鍵字所在行號
-
-A n #顯示關鍵字後n行
-
-B n #顯示關鍵字前n行
-
–exclude #搜尋時排除某些檔案
-
–exclude-dir #搜尋時排除某些目錄
-
-f #指定規則檔案進行搜尋
朋友會在“發現-看一看”看到你“在看”的內容