美文网首页
Linux搜索命令find和grep使用总结

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

作者: 文文太远了 | 来源:发表于2018-01-17 17:47 被阅读0次

    前言


    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/ 
    

    相关文章

      网友评论

          本文标题:Linux搜索命令find和grep使用总结

          本文链接:https://www.haomeiwen.com/subject/brpuoxtx.html