Linux搜索命令find和grep使用总结

前言


find和grep是Linux最基本的搜索命令,find用于搜索文件,grep用于搜索文件内容,熟练掌握其用法可以显著提高搜索效率,本文总结了两者的

  • 常规用法
  • 配合正则表达式使用
  • 两者结合使用
  • 配合shell脚本自定义搜索函数

1. find 基本用法


搜索包含res的文件
find "res"
结果中不仅会包含/res文件夹,也会包含res/strings.xml等文件
参数 -name 搜索仅匹配文件名而非相对路径
例:在当前路径搜索名称为strings.xml的所有文件
find ./ –name strings.xml
参数 -not 非
例:在当前路径搜索除了strings.xml文件外的所有文件
find ./ -not -name "strings.xml"
参数 -a 与
例:在当前路径搜索除了strings.xml文件外的所有xml文件
find ./ -not -name "strings.xml" -a -name "*.xml"
参数 -o 或
例:在当前路径搜索所有的xmljava文件
find . -name "*.xml" -o -name "*.java"
参数 -type 指定搜索的文件类型
例:在当前路径搜索所有文件夹
find . -type d
例:在当前路径搜索所有普通文件
find . -type f

2. grep 基本用法


在文件内搜索文件内容
例:在当前路径下的MainActivity.java文件中搜索onCreate方法
grep "onCreate" ./MainActivity.java
参数 -n 输出的结果打印行号
参数 -r 递归搜索
例:在当前目录以及子目录中搜索onCreate方法
grep -nr "onCreate"
使用-r参数后不需要加文件名
参数 -i 搜索忽略大小写
参数 -I 搜索结果只显示文件名
参数 -w 精确匹配结果
参数 -v 输出所有不匹配的行

3. find + 正则表达式(RE)


-name + RE 的使用

-name 是将文件名去匹配而不是文件的输出结果,以下为使用-name时的RE

符号 解释
* 代表任意字符(可以没有字符)
? 代表任意单个字符
[] 代表括号内的任意字符,[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 + RE 的使用

-regex 是将文件的输出结果进行匹配而不是文件名,使用-regex时必须使用正规的RE,以下为简单的RE使用

符号 解释
[] 代表括号内的任意字符,[abc]可以匹配a\b\c某个字符
[a-z] 可以匹配a-z的某个字母
[A-Z] 可以匹配A-Z的某个字符
[0-9] 可以匹配0-9的某个数字
. 表示任意单个字符
? 表示前面的字符出现一次或零次
+ 表示前面的字符至少出现一次
* 表示前面的字符出现零次或多次
() 将字符括起来后面跟量词
| 逻辑或,可以搜索两个条件

例1:搜索所有输出结果包含res的文件(即使文件名不包含res,只要该文件在res文件夹中也都可以被搜索到)
find . –regex “.*res.*”
注意此时用的是.*而不是*去匹配任意字符
例:在当前目录搜索所有文件名末尾为res或res_ext的文件
find ./ -regex “.*res|.*res_ext”

4. grep + 正则表达式 (RE)


find中的RE使用均可使用,注意有些符号需要用\转义,其他常用符号如下

符号 解释
< 单词的开始
> 单词的结束
^ 行的开始,^ 用在 [ ] 内表示不匹配其中的字符,注意区别
$ 行的结束
{n} 表示前面的字符匹配n次
{n,m} 表示前面的字符匹配n-m次
{,m} 表示前面的字符至多匹配的m次
{n,} 表示前面的字符至少匹配n次

egrep

egrep是grep的进化版,改进了许多grep中不方便之处如下,egrep使用RE符号 + , ? , | (或) , {} 时不用转义,如果要用其本身则需要转义,因此推荐使用egrep和RE配合使用

例1:搜索精确匹配Dialer单词的行(形如DialerActivity则不会匹配)
egrep –nr “\<Dialer\>”
例2:当前目录搜索以private开始的行(private前可能有空格)
egrep -nr "^.*private"

5. find和grep结合使用


面对大量代码时仅使用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文件内容,使用jgrep搜索效率远胜于单单使用grep进行搜索,下面对这个函数进行分析
find
在当前目录搜索
-o
或,并列多个条件
-name .repo –prune
忽略.repo目录(git库相关)
-name .git –prune
忽略.git目录(git库相关)
-name out –prune
忽略out目录(编译生成的目录)
-type f
指定文件类型为普通文件
-name "*.java"
指定匹配的文件名为.java文件
-print0 | xargs -0
忽略搜索中可能出现的错误信息,并将搜索到的文件作为结果向后传递并继续执行
grep --color –n
用grep在之前搜索到的文件中进行内容搜索,输出行号并标识颜色
"$@"
表示在使用jgrep函数时输入的参数,这里即为egrep搜索的内容

管道符号以及xargs的使用

上例中的|为管道符号,作用是将前一个命令的标准输出作为后一个命令的标准输入。

如果仅使用|,那么前面的结果会作为输入直接传递到后面的命令中,而使用xargs,就可以使前面的结果作为参数传递到后面的命令中,而这个特性对于find和grep而言十分重要。

例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 通话

该例中xargs后使用了-i参数,该参数的作用是可以将后面命令中的 {}符号视为前面find搜索的结果文件。本例中连续使用了两次xargs进行结果的传递

例3:在当前目录中的所有mk文件中搜索ro.build.type

find . –type f –name “*.mk” –print0 | xargs -0 grep –n –color “ro.build.type”

本例中和之前提到的jgrep函数都使用了–print0 | xargs -0进行结果传递而非单纯使用xargs,这样做的好处是如果find搜索会忽略可能出现的错误,使最终输出的结果更清晰,因此在使用xargs时建议按照–print0 | xargs -0方式书写命令

6. 编写搜索函数

find和grep的结合使用的命令较长,为方便起见,我们需要使用函数配合使用(形如上述的jgrep函数)。
下例中说明了如何编写搜索函数以及如何在Linux命令行中使用函数,这里可能需要用到简单的shell脚本命令:

  • 编写简单的搜索函数

首先创建test.sh脚本文件并编写下述代码

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 "$@"
}

函数的使用

#加载函数脚本,只需加载一次
source test.sh
#在当前目录及子目录下的所有.mk文件中搜索Dialer
mkgrep Dialer
  • 编写复杂的搜索函数

首先创建test.sh脚本文件并编写下述代码

#文件内容搜索函数sep
#参数1 必选 搜索内容
#参数2 可选 前缀-t 内容所在的文件类型(即文件后缀名,如java),缺省为所有文件类型
#参数3 可选 前缀-f 指定搜索的目录 缺省为当前目录及所有子目录
#用例 sep "ITelecomService.Stub"  -t  java aidl -f  packages/ frameworks/ 
#用例解析 在packages、frameworks目录中的所有java、aidl文件中搜索"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
}

函数的使用

#加载函数脚本,只需加载一次
source sep.sh
#在当前路径下的packages、frameworks目录中的所有.java和.aidl文件中搜索ITelecomService.Stub
sep "ITelecomService.Stub"  -t  java aidl -f  packages/ frameworks/ 
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271