前言

关于本文

总 结 了 find、grep常 规 用 法,正 则 表 达 式,find与 grep合 用 以 及 自 定 义 搜 索 函 数 等

什么是find和grep

find 和 grep 是 linux中 最 常 用 的 两 个 搜 索 函 数,本 文 将 会 介 绍 并 例 示 这 两 个 函 数 的 用 法。

为什么要用find和grep

对 其 的 熟 练 掌 握 可 以 明 显 提 高 搜 索 效 率,尤 其 是 面 对 动 辄 几 十 G 源 码 时 。

关 于 参 数

find和grep有很多参数,可以用以下命令导出查看:

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

参数可以帮助我们在使用时提高效率,实现特定需求以及避免错误,本文会介绍一些常用参数。

两者的区别,用find还是用grep

关于用find还是用grep,只要掌握一个原则就可以了:

凡是搜索文件名,就用find

凡是搜索文件内容,就要grep(当然为了提高效率可以结合find使用,后面会讲)

find基本用法

搜索文件名

例:在当前目录搜索名称为DialactsActivity.java的文件

find ./ –name DialactsActivity.java
 

参数 –a  –o  –not

分别为与、或、非的意思,相当于find中的逻辑运算

例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
 

参数 –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

用于指定查找文件的大小(单位b、k、M、G)

例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

查找匹配忽略大小写,默认状态下会匹配大小写

参数 –l(L的小写,不是大写的i)

输出结果只显示文件名,不显示行

参数 -s

不显示不存在或无匹配文件的错误信息

参数 –w

可以精确匹配后面的单词,而不是字符串匹配

参数 -v

逆反模式,即输出不匹配的所有行

grep中RE的使用以及egrep

find中所说的REgrep这边都可以使用,后面不再赘述,需要注意的是 + 、?要用\转义

什么是egrep

egrep是grep的进化版,改进了许多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搜索,这样会相当耗时,因此,我们需要掌握一些技巧以使搜索变得简单而又高效:

find和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)
这么分析下来,这个函数的意思应该很容易就可以理解了,在这个基础上,大家可以根据实际情况举一反三,以写出适合自己的函数或者命令。
 

find、grep中xargs 和 | 的使用

|       :管道命令符,它会将前一个命令的标准输出作为后一个命令的标准输入,这里不展开了,具体作用可以自行寻找资料学习。
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文件,实用性也很强。
 

find & grep 总 结的更多相关文章

  1. KMP算法总♂结

    讲KM♂P算法之前,我们先讲一个故♂事. 有一天,sgg给了老obo一封信和一个单词,并给他一个任务:找出这封信出现了多少个单词,然后在规定时间内告诉他. 碰到这个问题,老obo会怎么做呢? 首先最直 ...

  2. 转:用​C​语​言​的​r​a​n​d​(​)​和​s​r​a​n​d​(​)​产​生​伪​随​机​数​的​方​法​总​结

    标准库<cstdlib>(被包含于<iostream>中)提供两个帮助生成伪随机数的函数: 函数一:int rand(void): 从srand (seed)中指定的seed开 ...

  3. W​o​r​d​P​r​e​s​s​常​用​标​签​和​调​用​总​结

    调用头部模板<?php get_header();?> 调用尾部模板<?php get_footer();?> 调用侧边栏<?php get_sidebar();?> ...

  4. android WebView总 结

    浏览器控件是每个开发环境都具备的,这为马甲神功提供了用武之地,windows的有webbrowser,android和ios都有webview.只是其引擎不同,相对于微软的webbrowser,and ...

  5. Linux命令:grep,报错Binary file (standard input) matches

    在Linux使用grep命令,从文件中抓取显示特定的信息,如下: cat 文件名 | grep 特定条件 --->   cat xxxx | grep 12345 结果报错:Binary fil ...

  6. Linux系统诊断必备技能之一:lsof 用法详解!

    lsof(list open files)是一个查看当前系统文件的工具.在linux环境下,任何事物都以文件的形式存在,用户通过文件不仅可以访问常规数据,还可以访问网络连接和硬件:如传输控制协议 (T ...

  7. <摘录>Linux 环境下编译 0.11版本内核 kernel

    系统环境:Fedora 13 + gcc-4.4.5 最近在看<linux内核0.11完全注释>一书,由于书中涉及汇编语言的地方众多,本人在大学时汇编语言学得一塌糊涂,所以实在看不下去了, ...

  8. 超长可视化指南!带你理清K8S部署的故障排查思路,让bug无处遁形

    本文将帮助你厘清在Kubernetes中调试 deployment的思路.下图是完整的故障排查思路,如果你想获得更清晰的图片,请在公众号后台(RancherLabs)回复"troublesh ...

  9. IoT设备实践丨如果你也在树莓派上部署了k3s,你也许需要这篇文章

    前 言 树莓派是一种广泛流行的开发板,随着物联网的深入发展,树莓派大有成为IoT终端设备标准之趋势.在支持客户在IoT场景中落地k3s时,k3s在树莓派上的部署问题也就出现了.本文记录了一些其中的关键 ...

随机推荐

  1. vim和emacs

    vim和emacs 在编程界一直有两大神器的传说.这两大神器一个是emacs,一个是vim.一个是神的编辑器,一个是编辑器之神. 程序员的圈子里面也一直流传着一个段子,说是世界上的程序员分为三种.使用 ...

  2. LOJ #6402. yww 与校门外的树 多项式求逆

    蛮神的一道题. code: #include <cmath> #include <cstring> #include <algorithm> #include &l ...

  3. Codeforces 1303E. Erase Subsequences 代码(dp 字符串压缩一维状态优化)

    https://codeforces.com/contest/1303/problem/E #include<bits/stdc++.h> using namespace std; ; i ...

  4. C# GZip Compress DeCompress

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. How to Install Oracle Java 11 on Ubuntu 18.04 LTS (Bionic) Written by Rahul, Updated on April 3, 20

    本文系转载备份 请阅读点击下面链接阅读原文以获取更佳地阅读体验.谢谢. How to Install Oracle Java 11 on Ubuntu 18.04 LTS (Bionic) Writt ...

  6. npm vs yarn

    npm yarn npm install yarn npm install react --save yarn add react npm uninstall react --save yarn re ...

  7. Laradock + tp5 + nginx 配置虚拟机域名始终跳转首页/502报错

    laradock默认配置文件如下: 配置运用于本地windows+phpstudy 部署的laravel项目未出现问题,如下: server { listen ; listen [::]:; serv ...

  8. mybatis一级缓存和二级缓存(三)

    缓存详细介绍,结果集展示 https://blog.csdn.net/u013036274/article/details/55815104   配置信息 http://www.pianshen.co ...

  9. nginx 启动报错找不到nginx.pid文件

    这个问题的出现应该是系统找不到nginx的配置文件nginx.conf,所以,我们要告诉系统配置文件的位置:' --- 使用nginx -c /usr/local/nginx/conf/nginx.c ...

  10. PHP不使用第三个变量,如何实现两个变量值互换(变量值自定)

    1.使用函数: $a = 123; $b = 456; list($b,$a) =array($a,$b); 2.数学算式:$a =$a+$b-$b; $a =2; $b =1; $a =$a+$b; ...