總 結 了 find、grep常 規 用 法,正 則 表 達 式,find與 grep合 用 以 及 自 定 義 搜 索 函 數 等java
find 和 grep 是 linux中 最 常 用 的 兩 個 搜 索 函 數,本 文 將 會 介 紹 並 例 示 這 兩 個 函 數 的 用 法。linux
對 其 的 熟 練 掌 握 可 以 明 顯 提 高 搜 索 效 率,尤 其 是 面 對 動 輒 幾 十 G 源 碼 時 。git
find和grep有不少參數,能夠用如下命令導出查看:正則表達式
man grep > grep.txt man find > find.txt
參數能夠幫助咱們在使用時提升效率,實現特定需求以及避免錯誤,本文會介紹一些經常使用參數。shell
關於用find仍是用grep,只要掌握一個原則就能夠了:bash
凡是搜索文件名,就用findide
凡是搜索文件內容,就要grep(固然爲了提升效率能夠結合find使用,後面會講)函數
例:在當前目錄搜索名稱爲DialactsActivity.java的文件學習
find ./ –name DialactsActivity.java
分別爲與、或、非的意思,至關於find中的邏輯運算ui
例1:在當前目錄搜索除了AndroidManifest.xml文件之外其餘的xml文件
find ./ –not –name AndroidManifest.xml –a –name 「*.xml」
例2:在當前目錄搜索名稱爲values-zh-rCN或values的文件
find ./ -name values-zh-rCN -o -name values
該參數的做用是忽略某個文件,即不在這個文件夾裏搜索文件以提升效率,該參數常和-o一塊兒使用
例1:在當前目錄且不在res文件中搜索名爲values-zh*的文件並打印
find ./ -name res -prune -o -name values-zh* -print
Note:最後的-print,若是不加-print結果中除了打印不在res文件中的values-zh*文件以外還會打印find . -name res這個搜索出來的結果
tips:*爲通配符
find命令後加入該參數能夠對搜索結果進行處理
例:在當前目錄搜索全部java文件並將其刪除
find ./ –name 「*.java」 –exec rm –rf {} \;
Note:{} 表示前面搜索的結果, 「; 」表示命令結束, 「 \ 」用於轉義且前面必需要有空格
該參數用於指定查找文件的類型
例1:在當前目錄查找文件名包含res的文件夾
find ./ –name 「*res*」 –type d
-type參數後跟指定的文件類型,d爲文件夾,f爲普通文件
用於指定查找文件的大小(單位b、k、M、G)
例1:在當前目錄查找全部小於10k的文件
find ./ –size -10k
例2:在當前目錄查找全部大於10M的文件
find ./ –size +10M
-name 是將文件名去匹配而不是文件的輸出結果 * : 表明任意字符(能夠沒有字符) ? : 表明任意單個字符 [] : 表明括號內的任意字符,[abc]能夠匹配a\b\c某個字符 [a-z] : 能夠匹配a-z的某個字母 [A-Z] : 能夠匹配A-Z的某個字符 [0-9] : 能夠匹配0-9的某個數字 若是方括號內加入「 ^ 」,則表示不去匹配裏面的字符 [^a-z] : 表示不匹配a-z的某個字符。 例1 : 在當前目錄中搜素不以a、b、c開頭的全部文件 find ./ –name 「[^abc]*」 例2:在當前目錄中搜索以大寫字母或數字開頭的全部文件 find ./ -name 「[A-Z0-9]*」
-regex是將文件的輸出結果進行匹配而不是文件名
好比,當前目錄中有a文件夾,a中有b文件夾,b中有c文件
那c文件的文件名爲c,輸出結果爲./a/b/c,前者用於-name匹配,後者用於-regex匹配
-regex相對於-name的優點是可使用正規的RE
例:搜索全部輸出結果包含res的文件(哪怕文件名不包含res,只要該文件在res文件夾中也均可以被搜索到)
find . –regex 「.*res.*」
Note:這裏匹配全部字符是 .* 而不是 *
[] : 與以前find中描述相同,在此不予贅述 . : 表示任意單個字符 ? : 表示前面的字符出現一次或零次 + : 表示前面的字符至少出現一次 * : 表示前面的字符出現零次或屢次 () :將表示的字符括起來後面跟量詞 例:在當前目錄搜索輸出結果至少出現一次res的全部文件 find ./ -regex 「.*\(res\)+.*」 Note :()要用\轉義,該例將會打印出全部包含res的目錄及其中的文件 | : 邏輯或,能夠搜索兩個條件 例:在當前目錄搜索全部文件名末尾爲res或res_ext的文件 find ./ -regex 「.*res|.*res_ext」
先用兩個例子看grep最簡單的用法
例1:在Android.mk文件中搜索包含res的行
grep 「res」 Android.mk
例2:在當前目錄的全部文件中搜索包含res的行
grep 「res」 ./*
表示在當前目錄和子目錄中循環搜索(加入該參數能夠不用指定文件,意爲已經指定了當前目錄及子目錄中的全部文件)
grep –r 「res」
輸出的結果打印行號
例:在當前目錄及子目錄中的全部文件中搜索包含res的行並打印行號
grep –nr 「res」
查找匹配忽略大小寫,默認狀態下會匹配大小寫
輸出結果只顯示文件名,不顯示行
不顯示不存在或無匹配文件的錯誤信息
能夠精確匹配後面的單詞,而不是字符串匹配
逆反模式,即輸出不匹配的全部行
find中所說的REgrep這邊均可以使用,後面再也不贅述,須要注意的是 + 、?要用\轉義
egrep是grep的進化版,改進了許多grep中不方便之處以下:
egrep使用RE符號 + , ? , | (或) , {} 時不用轉義,若是要用其自己則須要/轉義
因此,若是須要用到RE的話,儘可能選擇egrep
\< , \> :分別表示單詞的開始和結束,將單詞放入其中能夠精確匹配(相似於-w) 例:搜索精確匹配Dialer單詞的行(形如DialerActivity則不會匹配) egrep –nr 「\<Dialer\>」 Note: \>表示的是單詞的結束,單詞多是下一個單詞,這裏寫的時候須要注意 ^ , $ : 分別表示行的開始和結束(^ 用在 [ ] 內表示不匹配其中的字符,注意區別) {n} : 表示前面的字符匹配n次 {n,m} : 表示前面的字符匹配n-m次 {,m} : 表示前面的字符至多匹配的m次 {n,} : 表示前面的字符至少匹配n次 [ ] : 方括號使用和find同樣,也可使用國際模式,但感受不如直接寫形如[0-9a-zA-Z]易於理解,所以不予展開 [[:space:]] :表示空格或tab 例1:當前目錄搜索包含access your和Phone permission的行(若是中間的字符串看不清或者不方便寫或者多是轉義符如換行符等,能夠用.*代替) egrep –nr 「access your.*Phone permission」
前面說了這麼多,其實都是在爲這一小節作鋪墊,相信在實際應用中你們不會在源碼中直接去grep搜索,這樣會至關耗時,所以,咱們須要掌握一些技巧以使搜索變得簡單而又高效:
在實際應用中,find和grep配合使用將會很是方便而迅速,先看一個例子:
function jgrep() { find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.java" -print0 | xargs -0 grep --color -n "$@" }
這個是位於Android源碼build/envsetup.sh中的jgrep函數,用於搜索java文件內容,是常用的一個函數,是find結合grep的典型案例。若是已經肯定了搜索內容在java文件中,那麼相比於直接用grep進行全局搜索,這種先搜索全部的java文件,再在其中搜索內容的方式能夠顯著提升效率。
咱們先來解析一下這個函數: find . :在當前目錄搜索 -o : 或,並列多個條件 -name .repo –prune : 忽略.repo目錄(git庫相關) -name .git –prune : 忽略.git目錄(git庫相關) -name out –prune : 忽略out目錄(編譯生成的目錄)ds -type f :指定文件類型爲普通文件 -name "*\.java" : 指定匹配的文件名爲.java文件 -print0 | xargs -0 : 忽略搜索中可能出現的錯誤信息,並將搜索到的文件做爲結果向後傳遞並繼續執行 grep --color –n :用grep在以前搜索到的文件中進行內容搜索,輸出行號並標識顏色 "$@" :表示在使用jgrep函數時輸入的參數,這裏即爲grep搜索的內容(本人未搞清這裏爲何寫$@而不是$*、$1) 這麼分析下來,這個函數的意思應該很容易就能夠理解了,在這個基礎上,你們能夠根據實際狀況觸類旁通,以寫出適合本身的函數或者命令。
| :管道命令符,它會將前一個命令的標準輸出做爲後一個命令的標準輸入,這裏不展開了,具體做用能夠自行尋找資料學習。 xargs: 若是僅使用 | ,那麼前面的結果會做爲輸入直接傳遞到後面的命令中,而使用xargs,就可使前面的結果做爲參數傳遞到後面的命令中,而這個特性對於find和grep而言十分重要。下面舉幾個例子來講明find中xargs的用法: 例1:在當前目錄中搜索全部AndroidManifest.xml文件並在其中搜索DialtactsActivity find . –name AndroidManifest.xml | xargs grep –n –color 「DialtactsActivity」 說明:該例是xargs最基本的用法,若是將xargs去掉,那麼grep搜索的內容是find輸出的結果內容而非結果文件 例2:在當前目錄搜索全部的values-zh-rCN文件目錄並在其中搜索全部的strings.xml文件(即全部中文字符串存放位置),而後在搜索到的strings.xml文件中搜索「通話」字符串 find . –type d –name 「values-zh-rCN」 | xargs –i find {} –name 「strings.xml」 | xargs grep –n –-color 通話 tips:該例中xargs後使用了-i參數,該參數的做用是能夠將後面命令中的 {} 符號視爲前面find搜索的結果文件。本例中連續使用了兩次xargs進行結果的傳遞。 例3:在當前目錄中的全部mk文件中搜索ro.build.type find . –type f –name 「*.mk」 –print0 | xargs -0 grep –n –color 「ro.build.type」 tips:本例中和以前提到的jgrep函數都是用了 –print0 | xargs -0進行結果傳遞而非單純使用xargs,這樣作的好處是若是find搜索會忽略可能出現的錯誤,使最終輸出的結果更清晰,所以在使用xargs時建議按照–print0 | xargs -0方式寫命令。
學習find和grep的使用是爲了使用方便和提升效率,若是每次搜索都和上面的例子那樣敲一堆命令,雖然提升了效率,方便和使用性上卻大打折扣,所以,咱們須要將命令進行抽象,編寫搜索函數,就如同以前所講的系統自帶的jgrep函數同樣,作到真正的實用而又高效。
爲了更加直觀,舉一個例子來講明如何編寫搜索函數,這裏須要用到一些簡單的編寫shell腳本基礎知識:
#文件內容搜索函數sep #參數1 必選 搜索內容 #參數2 可選 前綴-t 內容所在的文件類型(即文件後綴名,如java),缺省爲全部文件類型 #參數3 可選 前綴-f 指定搜索的目錄 缺省爲當前目錄及全部子目錄 #用例 sep "new ITelecomService.Stub" -t java xml –f packages/ frameworks/ #用例解析 在packages、frameworks目錄中的全部java、xml文件中搜索"new ITelecomService.Stub" function sep() { #文件內容=第一個參數 se_content=$1 #文件類型和搜索目錄暫時=空 se_fileType="" se_folder="" #shift的做用是將第一個參數移除,即當前函數輸入的第二個參數變成第一個參數,第三個變成第二個,以此類推 shift #判斷當前第一個參數是否爲-t,即文件類型是否指定,若是指定就取出文件類型放入se_fileType變量中 if [ "$1" = "-t" ];then #若是是-t就將這個參數移除 shift while ( [ "$1" != "-f" ] && [ -n "$1" ] ) do se_fileType="$se_fileType $1" shift done fi #判斷當前第一個參數是否爲-f,即搜索目錄是否指定,若是指定就取出搜索目錄放入se_folder變量中 if [ "$1" = "-f" ];then #若是是-f就將這個參數移除 shift while [ -n "$1" ] do se_folder="$se_folder $1" shift done fi #判斷文件類型是否爲空,不爲空則創建循環分別搜索指定的文件類型 if [ -z $se_fileType ];then #這裏若是搜索目錄爲空find會自動搜索當前目錄及子目錄,所以不用再作判斷 #這裏用到了egrep而不是grep,方便輸入搜索內容時直接使用正則表達式 find $se_folder -type f -print0 | xargs -0 egrep -n --color "$se_content" else for ft in $se_fileType do find $se_folder -type f -name "*.$ft" -print0 | xargs -0 egrep -n --color "$se_content" done fi } 這個函數總體而言比較簡單,加上其中的註釋,想必你們能夠很容易理解,在這個基礎之上咱們還能夠添加其餘參數,好比是否精確匹配等,這裏再也不具體說明了。 關於函數如何使用:寫到.sh文件中再用source命令導入便可在命令行直接使用,這是linux中最基本的操做,不太明白的同窗可自行百度。 tips:也能夠仿照前面說的jgrep函數編寫簡單的函數以下: function mkgrep() { find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.mk" -print0 | xargs -0 grep --color -n "$@" } 只是把java改爲mk就能夠直接搜索全部mk文件,實用性也很強。