find之强大毋庸置疑,此处只是带领大家一窥find门径,更详细的说明见man find和 info find。
整篇文章循序渐进,从最常用的文件名测试项开始步步深入,到第六节基本讲完find处理文件的规则,再之后的章节是一些常用表达式的说明。
(此篇中所有选项及例子基于GNU find version 4.2.28)
整篇文章循序渐进,从最常用的文件名测试项开始步步深入,到第六节基本讲完find处理文件的规则,再之后的章节是一些常用表达式的说明。
(一)Get Start
最简单的find用法莫过于如此:
find命令的一般格式为:

其中,'-H' '-L' '-P'三个选项主要是用来处理符号连接,'-H'表示只跟随命令行中指定的符号连接,'-L'表示跟随所有的符号连接,'-P'是默认的选项,表示不跟随符号连接。
例如,在我的当前目录下有一个符号连接e1000,现在我想查找文件名中最后一个字母是数字的源文件,那么




格式中的 [path... ]部分表示以此目录为根目录进行搜索。
格式中的 [expression]是一个表达式。 最基本的表达式 分为三类:设置项(option)、测试项(test)、动作项(action),这三类又可以通过逻辑运算符(operator)组合在一起形成更大更复杂的表达式。设置项(如-depth,-maxdepth等)针对这次查找任务,而不是仅仅针对某一个文件,设置项总是返回true;测试项(test)则不同,它针对具体的一个文件进行匹配测试,如-name,-num,-user等,返回true或者false;动作项(action)则是对某一个文件进行某种动作(最常见的如-print),返回true或者false。
正是[expression]部分的丰富,才使得find如此强大。此部分较复杂,后面慢慢说明。
(二)文件名
根据文件名来查找一个文件是大家经常遇到的事情,第一节中的'-name'正是解决此问题的。
-name属于表达式中的测试项(test),它按照文件名模式来匹配文件,若匹配则返回true,否则返回false。最好用引号将文件名模式引起来,防止shell自己解析要匹配的字符串。(可以用单引号也可以用双引号,单引号和双引号在shell环境中的区别见后续部分)
例如,想要的当前目录及子目录中查找文件名以一个大写字母开头或者以小写a或b开头的文件,可以用:





-name对大小写字母敏感,如果想匹配时不考虑大小写可以使用-iname测试项。'i'可以加在许多选项前面,比如-ipath,-iregex,-iwholename等等,都是表示大小写不敏感。
(三)正则表达式
使用上面的-name测试项能解决许多问题,但是有些还是不太好办,比如:查找当前目录下名称全部为数字的c源代码文件,这时就该'-regex'出手了。正则表达式绝对值得你去好好研究一下,在unix系统下太有用了,这里不做过多说明,请读者自行学习。
-regex同样属于测试项。使用-regex时有一点要注意:-regex不是匹配文件名,而是匹配完整的文件名(包括路径)。例如,当前目录下有一个文件"abar9",如果你用"ab.*9"来匹配,将查找不到任何结果,正确的方法是使用".*ab.*9"或者".*/ab.*9"来匹配。
针对上面的那个查找c代码的问题,可以这么写:


还有一个设置项(option)'-regextype',可以让你根据自己的喜好选择使用的正则表达式类型,大家可以试试。
(四)wholename与path
既然上一节提到了完整文件名(包括路径名),那么这里不妨说一下-wholename和-path。
-wholename和-path都属于测试项(test),而且功能也一样。-path从字面上看给人一种错觉,好像只匹配路径名(或者目录名),其实它也可以匹配文件名,因此-wholename这个名字更贴切一些。
看看这个例子,当前目录下有一个phone目录,phone目录里有一个文件名称是puk.txt,使用-path:


另外要提一点:使用-path的一般格式是:find [path ...] -path pattern ...
它的意思是:在[path ...]部分指明的路径上,使用pattern匹配所有文件的完整文件名;而不是说在类似的pattern目录下查找文件。
(五)逻辑运算符
有了上面三个选项,你现在应该对文件名的相关匹配得心应手了,对于不是很复杂的查找应该也胜任了。但是看看这个例子,解释一下它在做什么?
$ find . -size +0c -wholename "*e*[0-9]