话说linux中我最常用的几个命令就是awk, grep, vim, find,今天我们就来详细看下find命令的使用
先来一个简单例子:
Shell代码
find . -name "*.java" # 递归查找当前目录下所有java文件
其中:
. 表示查找路径为当前目录(你也可以指定为其他工程目录,譬如:~/workspace/login)
-name 表示搜索的目标文件名或目录名(允许使用shell通配符)
通常上述命令已经能够完成你日常工作需求的80%,但是要想完成另外的20%,你必须再深入了解下find命令...
现在假设你需要查找Test.java 和 TEST.java这两个文件,这时候你该如何做?
也许你会find . -name "Test.java" 和 find . -name "TEST.java" 执行两遍
虽然这样做结果正确,但是有没有更简单的方式呢? 答案,自然有
Shell代码
find . -iname "test.java" # -iname 与-name参数含义一样,但是忽略大小写
发现没,是不是更优雅了...
现在我们更进一步,假设我们需要列出~/scripts目录下所有名为study的文件该如何做呢?
在不了解find命令之前,也许你需要使用shell for循环来递归遍历目录,然后对每个找到的study判断是否为文件(有可能是名为study的目录),若确实是文件则输出. 说了这么多,这个方式真的是繁琐异常,但是如果你了解find命令,那么just one line!
Shell代码
find ~/scripts -type f -name "study"
其中-type参数用来指定搜索的目标类型,f表示普通文件,-type还有其他常用的参数值:f-文件, d-目录
现在你已经了解了:
1.如何指定find搜索路径
2.如何指定find搜索的目标类型(-type)
3.如何指定find搜索的文件名或是目录名(-name / -iname)
真是不少东西了呢,不过我们要继续前行,find命令还有很多很有用的参数。
find命令默认是递归搜索,它的搜索算法应该是我们常说的深度优先遍历(可以通过指定-depth参数指定采用广度优先遍历算法),但是有时候我们希望仅在当前目录搜索,或是能够指定递归查找的深度,这时候该如何做呢? 两个字简单
-maxdepth: 指定递归查找时的目录最大深度,若为1,表示仅在当前目录查找
-mindepth: 指定递归查找时的目录最小深度
现在我们看两个例子(先不要尝试去运行):
Shell代码
find . -name "*.java" -maxdepth 3 find . -maxdepth 3 -name "*.java"
这两个命令看似没有什么差异,但是运行效果确相差万里(特别是当文件很多目录又非常深时),或者在有的机器上第一种形式根本无法运行,原因为什么呢?
因为第一个命令它首先会找出所有java文件,然后再筛选出满足深度条件的文件,这样效率非常非常之低,而第二个命令则仅仅是在1-3层目录下搜索目标文件,而没有对整个文件树进行递归遍历,所以效率很高.
在我的机器上执行第一种命令,弹出以下警告:
find: warning: you have specified the -maxdepth option after a non-option argument -name, but options are not positional (-maxdepth affects tests specified before it as well as those specified after it). Please specify options before other arguments.
好了,你现在你的手上又多了两把利器 -maxdepth 和 -mindepth(这个两个参数,可以提高你的查找效率以及zhuangbility)
find命令还几个很有用的参数
-mtime: 文件内容最后修改时间
-atime: 文件最后访问时间
-ctime: 文件meta信息最后修改时间(譬如文件权限)
这几个参数后面需要跟一个整型值使用,eg:
Shell代码
find . -mtime 1 -name "*.java" # 在当前目录下递归查找距离现在整1天修改的java文件 find . -mtime -1 -name "*.java" # 在当前目录下递归查找1天内修改的java文件 find . -mtime +1 -name "*.java" # 在当前目录下递归查找1天前修改的java文件
如果你需要查找某个时间段内的修改的文件,这些命令就非常有效了(搞运维的同学应该经常使用)
说了这么多参数(-name, -iname, -type, -mindepth, -maxdepth, -mtime等等),想必你对find命令已经有所了解,
现在我们来看看find命令的一个好基友----xargs
通常我们需要对查找出来的文件执行某些action,譬如我想查找某个工程目录下所有使用到StringUtils的java文件,这时候该怎么办呢?
方法1我们可以使用eclipse的搜索,方法2我们可以编写脚本,方法3 just one line ...
Shell代码
find ~/worksapce/project -name "*.java" | xargs grep "StringUtils"
其中:
find ~/worksapce/project -name "*.java" 将会在家目录下workspace/project中递归查找所有java文件
xargs grep "StringUtils" 表示在文件中(find命令查找出的结果集)查找含有StringUtils字样的文件
也许有人一开始会这样写:find ~/worksapce/project -name "*.java" | grep "StringUtils"
这个命令执行将不会产生任何结果,而原因就是因为没有使用xargs!
现在我们就来说说xargs:xargs是用来把输入流转化为参数的命令(默认把输入流中的空白字符譬如"\n"(换行)替换成" "(空格))
Shell代码
$ cat test a b c d e $ cat test | xargs a b c d e
ind命令将查找出的每一个文件名或目录名默认用"\n"分割,然后通过管道 | 作为输入流传递给grep命令,但是grep命令要求输入流必须是参数的形式,譬如:grep "target" file1 file2 所以必须使用xargs重新将输入流转换为参数
说到这里,一些比较严谨的同学也许会说,这样的命令:find ~/worksapce/project -name "*.java" | grep "StringUtils" 是不严谨,不安全的(这里还谈不上不安全,毕竟只是一个grep命令,但要是变成xargs rm -rf 那就危险了),原因就是find命令默认用"\n"分隔结果列表,而xargs会把"\n"转化成空格,所以当文件路径或者文件名含有"\n"这些字符时,就会被错误替换,这时候你在执行个rm -rf ,哦, 卖糕的...
所以我们应该养成好习惯,这样写
Shell代码
find ~/worksapce/project -name "*.java" -print0 | xargs -0 grep "StringUtils"
print0用'\0'(空字符)分隔结果列表,xargs -0 只会将'\0' 替换成空格,这样就不会出现刚才所说的问题了....
关于find命令,我就说到这里,赶紧尝试吧...
更多Find命令实战相关文章请关注PHP中文网!