总 结 了 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文件,实用性也很强。