前言

之前介紹過很多linux下查找相關的命令,例如《Linux中的文件查找技巧》,《find命令高級用法》,《如何查看linux中文件打開情況-lsof命令》等等,而對文件內容搜索的命令似乎還沒有涉及,因此本文介紹文本搜索命令--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 #指定規則文件進行搜索

本文最新地址Linux grep命令實例詳解

微信公眾號【編程珠璣】:專註但不限於分享計算機編程基礎,Linux,C語言,C++,數據結構與演算法,工具,資源等編程相關[原創]技術文章,號內包含大量經典電子書和視頻學習資源。歡迎一起交流學習,一起修鍊計算機「內功」,知其然,更知其所以然。


推薦閱讀:
相关文章