find 忽略文件夹选项-prune的说明

注意:因为习惯在当前路径查找时候,常忽略./ 的指定,但读者不要因此而完全忘记find的格式。

查找时忽略指定目录,是要使用-prune选项,但实际上最重要的还是要和path配合。-prune的意义是,当路径字串匹配了path中指定的目录时 候,find命令不进入这个目录查找,所以这个选项使用的关键,还是在path选项上的使用,也就是path选项和其他选项的配合使用,才能最后确定最终 结果。而path,实际上是对路径字串的一个字符匹配,但也并不仅仅只匹配于目录,文件同样可以被匹配,譬如存在一个目录结构
./01.txt
./02.txt
./03.txt
./aaa
./aaa/04.txt
./aaa/05.txt

find . -path "./aaa*" -print   匹配中使用*通配符,则会输出
./aaa
./aaa/04.txt
./aaa/05.txt

而如果是find . -path "./aaa" -print ,严格等于./aaa目录,则只输出
./aaa

而且*通配符会将路径中的字符"/"也作为普通字符进行贪婪匹配,所以可以匹配到目录以下的文件,所以在使用这个选项时候不要误以为这个只对目录有效,实际上只是一种路径字符匹配工具。

如果加上-prune,则第一个命令效果是:
find . -path "./aaa*" -prune -print
./aaa
因为加入了-prune,在匹配这个目录同时禁止进入到这个目录下搜索,于是也就是我们所需要的不进入某个目录查找。

但如何配合其他选项来使用-path 以及-prune呢?以-name为例,下面对于配合使用方法进行一下演示。

我们先来看看纯粹的-name和-path配合使用是什么效果:
find -name "*.txt" -path "./aaa" -print
这个命令也相当于
find -name "*.txt" -a -path "./aaa" -print,但一般的-a都被忽略不写。这个命令对于上面的目录结构这个命令执行为空结果。也就是,既要文件名称匹配"*.txt",同时又要其路径字 串匹配"./aaa",而文件名匹配"*.txt"的结果有:
./01.txt
./02.txt
./03.txt
./aaa/04.txt
./aaa/05.txt
路径字串匹配 "./aaa"的只有
./aaa
二者取and则为空结果,所以上面的命令输出为空。


如果对-path选项加上-prune,
find -name "*.txt" -path "./aaa" -prune -print
实际上与上面那条命令输出并无区别,只是禁止进入./aaa下匹配而已,但最终的结果仍然是空。

再来看看很多人会误用的结构:
find -name "*.txt" -path "./aaa" -prune -o -print
也就是比上一条语句在-print前增加一个-o。但实际上这条命令是将当前目录以及包含./aaa子目录下的所有文件都打印出来。实际上
,这个语句先执行-o左侧的语句,find -name "*.txt" -path "./aaa" -prune,因为匹配为空,则执行-o右侧的语句-print,也就是把不匹配左侧的文件名打印出来,既然左侧没有匹配为真的,所以也就是所有的文件都被打印。


这里要留意的是匹配模式项(比如-name "*.txt", -path ....),关系符( -a, -o,  ","),与操作符(-print, -exec,- ok)之间的位置关系,特别是操作符在关系符的不同位置上,对于结果也具有决定的作用。

比如一个语句
find -name "*.txt" -print -o -path "./aaa" -prune -print             (1)
其实也可以略写为
find -name "*.txt" -o -path "./aaa" -prune
注意第二个语句-o两侧都没有-print,输出结果为:
./01.txt
./02.txt
./03.txt
./aaa    

这是因为find开始执行,遇到第一个-print命令,则会考虑输出,但是输出的时候,则是将剩余所有的匹配项一起进行匹配操作,也就是执行的是
find -name "*.txt" -print -o -path "./aaa" -prune  (注意-print命令的位置)
这个命令执行中相当于
find -path "./aaa" -prune -o -name "*.txt" -print
也 就是在匹配过程中,对于包含了-print部分的匹配项是最后匹配的,因此先匹配到了./aaa路径,由于-prune的存在禁止进入这个路径查找,禁止 进入查找,并不会因为-o选项而被逆转,所以左侧匹配了./aaa后,-o右侧则是不匹配./aaa项目剩余的文件继续去匹配-name模式,匹配的结果 最后被-print打印出来,这也就是我们所期待的忽略某个指定目录进行搜索的结果。

但是我们要分析的是命令(1)中的结果,命令(1)在遇到第一个-print命令后并执行了输出,但是这个find命令中还存在第二个-print命令,所以在输出
./01.txt
./02.txt
./03.txt
结果后,还是要继续执行,要执行最后一个-print命令,下面的执行则相当于执行一个
find -name "*.txt" -o -path "./aaa" -prune -print
-o左侧匹配-name "*.txt",-o到右侧后则是对不能匹配到-name模式的结果,进行-path匹配,输出结果为
./aaa
所以(1)命令最终的输出结果就是
./01.txt
./02.txt
./03.txt
./aaa 。

-a, -o都常见了,但是实际中还可以存在“,“的使用,例如新建一个aaa1目录,其下有08.txt等文件,若执行
$ find -name "*.txt"
./01.txt
./02.txt
./03.txt
./aaa/04.txt
./aaa/05.txt
./aaa1/08.txt
./aaa1/09.txt

若忽略aaa和aaa1目录查找txt文件,则可以写做
$ find -name "*.txt" -print -o -path "./aaa" -prune , -path "./aaa1"  -prune  (注意","两侧的空格不可忽略)
./01.txt
./02.txt
./03.txt

这也就是同时忽略几个目录的写法,注意每忽略一个目录,其后都要跟随一个-prune,而不能几个-path公用一个-prune。

其实若没有-prune的使用,也可以忽略某个目录下文件的匹配,譬如
$find -path "./aaa*" -o -name "*.txt" -print
./01.txt
./02.txt
./03.txt
同样可以不匹配到./aaa目录下的文件,但是这里实际上是搜索过./aaa目录下的文件并且进行匹对的,只是因为-print在-o的右侧输出,而./aaa下的文件被匹配是在-o的左侧,所以最终的结果是达不到被打印输出的条件。但效率应当是明显低于使用-prune选项。

原文地址:https://www.cnblogs.com/dawq/p/5777522.html