
2.3.6 Linux下的搜索神器——find
本小节介绍Linux下的搜索神器find命令,find功能强大且使用非常频繁,如果能够很好地使用find命令,将大大提升Linux下的工作效率。本小节将通过多个示例来介绍find的典型用法。
1.示例1:查找名字确定的文件/目录
假设用户要查找文件year.c,仅知道该文件位于 /usr/local目录下,但具体位于哪个子目录下不清楚。因此,需要使用find命令,来确定year.c的完整路径,具体命令如下,/usr/share是要查找的路径,-name指定查找对象的名字,即year.c。注意命令、选项和参数之间都要有空格。

结果显示如下,可以看到year.c的绝对路径。

2.示例2:查找名字不确定的文件/目录
如果不确定查找对象的名字,例如记不清楚要查找的文件是year.c,只记得该文件是一个C语言代码文件,以c作为扩展名。那么可以使用通配符 * 进行查询匹配,示例如下。

结果会显示 /usr/share目录下所有以c为扩展名的文件的绝对路径,可以在结果中筛选出想要的结果。

find支持通配符,其中*表示任意字符串,?表示单个字符。
find也支持范围表示,例如使用[a-z]可以表示从a~z的单个字符,[0-9]表示从0~9的单个数字。
3.示例3:按照类型查找的文件/目录
-type选项可以实现按文件类型查找,例如查找 /dev/ 目录下所有的块设备文件,命令如下,其中-type指定文件类型,b表示块设备文件,注意-type和b之间有空格。

find后面要跟查找路径/dev/,-type b不能放到/dev/的前面。
如果不需要进行文件名的匹配,可以省略-name"*"。
文件类型中,b表示块设备文件,c表示字符设备文件,d表示directory,p表示命名管道,f表示普通文件,l表示符号链接/软链接,s表示套接字文件,D表示door类型文件(Solaris)。
4.示例4:命令组合(一)
-exec选项可以将查找命令和其他命令结合起来,对查找的结果做二次处理。例如将/etc/下所有的sh文件复制到当前目录mysh下,步骤说明如下。
创建目录mysh,命令如下。

使用find将/etc/下所有扩展名为sh的文件复制到mysh目录,命令如下。

上述命令和参数说明如下。
● find/etc/-name"*.sh"表示查找/etc/目录下所有扩展名为sh的文件。
● -exec指定处理find结果的命令为cp。
● {}表示find的搜索结果,即sh文件的绝对路径将作为cp的源文件参数。
● mysh是cp的目的路径。
● \; 中的\是一个转义字符,它告诉bash不要再把 ; 当作分隔符处理,而是当作一个普通的字符,那么,此时 ; 就是一个普通的字符,它将作为exec的最后一个参数,即结束标识。如果不加 \,那么 ; 会被bash当成特殊符号(即语句的分隔符)进行处理,而不会作为exec的参数。因此,不管-exec后面连接的是什么命令,最后都要以 \; 结尾。
也可以用另外一种方式实现以上示例的功能,命令如下,其中$(find /etc/ -name "*.sh")会将find的结果转换成cp命令的输入参数。

5.示例5:命令组合(二)
本例使用find + -exec统计/etc下扩展名为sh的文件的代码行数,命令如下,wc用来统计文本文件中的行数,-l是选项,表示打印行数。

也可以采用下面的命令。

执行结果如下,会打印每个sh文件的行数。

换一种实现方法,使用管道将find的输出(stdout)作为wc的输入,命令如下。

执行结果是10,如下所示。

为什么输出结果不是每个文件的行数呢?这是因为,find的输出是一个整体,其中包含了10个sh文件的绝对路径,以此作为wc的输入(这个输入可以认为是一个文件,该文件包含了10条绝对路径),因此,wc的输出就是10。而在前面的-exec或$(find /etc/ -name "*.sh")中,find的输出被分解成了一个个的参数(共10个),wc会对每个参数进行处理,从而输出每个文件的行数。