find & grep 總 結

find & grep 總 結

前言

關於本文

findgrep 法,正 式,find grep java

什麼是findgrep

find grep linux 數,本 法。linux

爲何要用findgrep

率,尤 G git

關 於 參 數

findgrep有不少參數,能夠用如下命令導出查看:正則表達式

man grep > grep.txt
man find > find.txt

參數能夠幫助咱們在使用時提升效率,實現特定需求以及避免錯誤,本文會介紹一些經常使用參數。shell

二者的區別,用find仍是用grep

關於用find仍是用grep,只要掌握一個原則就能夠了:bash

凡是搜索文件名,就用findide

凡是搜索文件內容,就要grep(固然爲了提升效率能夠結合find使用,後面會講)函數

find基本用法

搜索文件名

例:在當前目錄搜索名稱爲DialactsActivity.java的文件學習

find ./ –name DialactsActivity.java


參數 –a  –o  –not

分別爲與、或、非的意思,至關於find中的邏輯運算ui

1:在當前目錄搜索除了AndroidManifest.xml文件之外其餘的xml文件


find ./ –not –name AndroidManifest.xml –a –name 「*.xml」


2:在當前目錄搜索名稱爲values-zh-rCNvalues的文件

find ./ -name values-zh-rCN -o -name values


參數 –prune

該參數的做用是忽略某個文件,即不在這個文件夾裏搜索文件以提升效率,該參數常和-o一塊兒使用

1:在當前目錄且不在res文件中搜索名爲values-zh*的文件並打印

find ./ -name res -prune -o -name values-zh* -print


Note最後的-print,若是不加-print結果中除了打印不在res文件中的values-zh*文件以外還會打印find . -name res這個搜索出來的結果

tips*爲通配符

參數 –exec

find命令後加入該參數能夠對搜索結果進行處理

例:在當前目錄搜索全部java文件並將其刪除

find ./ –name 「*.java」 –exec rm –rf {} \;


Note{} 表示前面搜索的結果, 「; 」表示命令結束, \ 」用於轉義且前面必需要有空格

參數 –type

該參數用於指定查找文件的類型

1:在當前目錄查找文件名包含res的文件夾

find ./ –name 「*res*」 –type d


-type參數後跟指定的文件類型,d爲文件夾,f爲普通文件

參數 –size

用於指定查找文件的大小(單位bkMG

1在當前目錄查找全部小於10k的文件

find ./ –size -10k

2:在當前目錄查找全部大於10M的文件

find ./ –size +10M


find搜索匹配進階及RE(正則表達式)

-name

-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

-regex是將文件的輸出結果進行匹配而不是文件名

好比,當前目錄中有a文件夾,a中有b文件夾,b中有c文件

c文件的文件名爲c,輸出結果爲./a/b/c,前者用於-name匹配,後者用於-regex匹配

-regex相對於-name的優點是可使用正規的RE

例:搜索全部輸出結果包含res的文件(哪怕文件名不包含res,只要該文件在res文件夾中也均可以被搜索到)

find . –regex 「.*res.*」

Note這裏匹配全部字符是 .* 而不是 *

簡單的RE符號及用法

[]     : 與以前find中描述相同,在此不予贅述
.        : 表示任意單個字符
?  : 表示前面的字符出現一次或零次
+       : 表示前面的字符至少出現一次
*       : 表示前面的字符出現零次或屢次
()       :將表示的字符括起來後面跟量詞
例:在當前目錄搜索輸出結果至少出現一次res的全部文件
         find ./ -regex 「.*\(res\)+.*」
Note     :()要用\轉義,該例將會打印出全部包含res的目錄及其中的文件
|       : 邏輯或,能夠搜索兩個條件
例:在當前目錄搜索全部文件名末尾爲res或res_ext的文件
         find ./ -regex 「.*res|.*res_ext」

grep基本用法

先用兩個例子看grep最簡單的用法

1:在Android.mk文件中搜索包含res的行

grep 「res」 Android.mk

2:在當前目錄的全部文件中搜索包含res的行

grep 「res」 ./*

參數 –r

表示在當前目錄和子目錄中循環搜索(加入該參數能夠不用指定文件,意爲已經指定了當前目錄及子目錄中的全部文件)

例:在當前目錄及子目錄中的全部文件中搜索包含res的行

grep –r 「res」

參數 –n

輸出的結果打印行號

例:在當前目錄及子目錄中的全部文件中搜索包含res的行並打印行號

grep –nr 「res」

參數 –i

查找匹配忽略大小寫,默認狀態下會匹配大小寫

參數 –lL的小寫,不是大寫的i

輸出結果只顯示文件名,不顯示行

參數 -s

不顯示不存在或無匹配文件的錯誤信息

參數 –w

能夠精確匹配後面的單詞,而不是字符串匹配

參數 -v

逆反模式,即輸出不匹配的全部行

grepRE的使用以及egrep

find中所說的REgrep這邊均可以使用,後面再也不贅述,須要注意的是 + 、?要用\轉義

什麼是egrep

egrepgrep的進化版,改進了許多grep中不方便之處以下:

egrep使用RE符號 + | (或) , {} 時不用轉義,若是要用其自己則須要/轉義

因此,若是須要用到RE的話,儘可能選擇egrep

簡單的RE符號及用法

\< , \>       :分別表示單詞的開始和結束,將單詞放入其中能夠精確匹配(相似於-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」


findgrep的在搜索中的實際應用-進階

前面說了這麼多,其實都是在爲這一小節作鋪墊,相信在實際應用中你們不會在源碼中直接去grep搜索,這樣會至關耗時,所以,咱們須要掌握一些技巧以使搜索變得簡單而又高效:

findgrep結合使用

在實際應用中,findgrep配合使用將會很是方便而迅速,先看一個例子:

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)
這麼分析下來,這個函數的意思應該很容易就能夠理解了,在這個基礎上,你們能夠根據實際狀況觸類旁通,以寫出適合本身的函數或者命令。

findgrepxargs | 的使用

|       :管道命令符,它會將前一個命令的標準輸出做爲後一個命令的標準輸入,這裏不展開了,具體做用能夠自行尋找資料學習。
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方式寫命令。

編寫搜索函數

學習findgrep的使用是爲了使用方便和提升效率,若是每次搜索都和上面的例子那樣敲一堆命令,雖然提升了效率,方便和使用性上卻大打折扣,所以,咱們須要將命令進行抽象,編寫搜索函數,就如同以前所講的系統自帶的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文件,實用性也很強。
相關文章
相關標籤/搜索