Linux下查找文件: find 命令(一)

find命令用于在指定目录中根据tests测试条件搜索符合tests测试条件的文件

abstract.jpg

概要

该命令的形式如下:

1
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [path...] [expression]

第一次看到该命令的人可能会被其复杂繁多的选项参数吓到。其实在日常开发中,很多选项并不多见。所以上述命令格式可以简化如下:

1
find [path...] [expression]

Path

即为查找文件的路径,命令将在指定目录及其子目录下进行查找文件,默认为当前路径

Expression

表达式,由option选项、test测试条件、action动作组成。option选项,均返回true。test测试条件即为当前文件的判定条件,其返回true/false;action动作是作用于当前文件的动作,其同样返回true/false。

如果在表达式中除了-prune外无其他action。则默认对整个表达式结果为true的文件执行 -print 动作,而不是直接在后面添加-print。 示例如下:

figure 1.jpeg

操作符

通常在表达式会包含多个option、test、action,如下代码 code 1 处所示。当未显式指定操作符时,默认为 “-a” (即AND)操作符,故其命令的完整形式为code 2处所示

1
2
find . -path './subTest' -iname "sub*";     # code 1
find . -path './subTest' -a -iname "sub*"; # code 2

常用操作符如下:

  • expr1 -a expr2 : AND 逻辑与,使用短路求值。亦可写为expr1 -a expr2。如果 expr1 结果为 false,expr2 将不会被执行
  • expr1 -o expr2 : OR 逻辑或,使用短路求值。如果 expr1 结果为 true,expr2 将不会被执行
  • ( expr ) : 由于 AND 逻辑与的优先级 高于 OR 逻辑或的优先级。故,可以通过添加括号改变默认的操作符优先级。需要注意的是,命令中的左右括号需要使用反斜杠进行转义。即,\( expr \)
  • ! expr : NOT 逻辑非。对expr的结果进行取反

示例如下:

figure2.png

Tests 测试条件

在日常开发中,tests 测试条件最为常用,现对常用的测试筛选项进行介绍:

根据文件名查找文件

根据文件名来查找文件,这也是日常最常用的:

1
2
-name <filename>    # 大小写敏感
-iname <filename> # 大小写不敏感

其中,文件名参数可以使用Linux的文件名通配符,注意其不是正则

figure-3.png

根据文件权限

根据文件(Linux下,目录也属于文件)权限来筛选文件,其有3种匹配模式

1
2
3
-perm num       # 严格匹配所给权限
-perm -num # 满足所给全部权限即可
-perm /num # 满足所给任一权限位即可
  • 严格匹配

其将严格匹配所给权限的0和1设置,即结果文件的权限码必须和给定权限码num完全一致

1
-perm num

figure-4.png

  • 满足所给全部权限位即可

对于给定权限码num,文件全部满足给定的权限位即可,对于多余的权限位并不敏感

1
-perm -num

figure-5.png

  • 满足所给任一权限位即可

对于给定权限码num,文件若存在任一一个满足给定的权限位即可,对于多余的权限位并不敏感

1
-perm /num

figure-6.png

排除某个目录

查找文件时,如果已经知道某个目录下不存在我们所需文件,可以在find中指定排除,以免浪费时间搜索。下述命令中的-path test条件用来判定是否存在指定路径。如果是,则其返回true,并根据逻辑与的短路求值策略继续执行-prune action动作,用于排除该路径

1
2
-path pathName -prune
-path pathName -a -prune
  • 示例1

1处查看检索当前目录下所有的内容,而2处则是查看除subTest目录外的文件

figure 7.jpeg

相信这里会让人疑惑的地方在于 -print 前面的 -o 或操作符,根据前文所述,-path ./subTest -a -prune 用于排除指定目录,然后-print是查看剩下的文件,中间应该是用 -a 与操作符来连接啊。好,那我们先将上面代码中的 -o -print 改为 -a -print。来看看会发生什么

figure-8.png

咦?这里竟然输出的结果是不是让人很吃惊…………竟然是我们需要排除的目录。其实,问题是在于我们没有理清find命令的执行逻辑,find是对path下的所有文件(目录文件夹也是文件的一种)依次去执行表达式,根据test条件的结果来判定是否执行action。对于本例而言,当对subTest目录进行判定时,-path ./subTest 测试条件结果肯定为true,然后执行-prune以不对该目录下的文件进行遍历搜索测试,其是一个action且结果恒为真。如果此时后面如果是-a -print,则对当前测试的文件(即,subTest目录)执行打印动作,而遍历其他文件(比如,bers文件)进行测试时,-path ./subTest 测试条件结果为false,根据短路求值策略,均不会执行 -prune动作和-print动作,故最终我们看到的输出结果,只有./subTest目录文件;同理,如果后面是-o -print的话,测试 ./subTest 目录文件时,-path ./subTest -prune 结果为true,由于后面是-o 与操作符,根据短路求值策略,其将不会执行-print动作,而遍历其他文件(比如,bers文件)进行测试时,-path ./subTest 测试条件结果为false,根据短路求值策略,其将不会执行-prune动作,且 -path ./subTest -prune结果为false。而对于-print动作而言,由于其前面为 -o 或操作符,将会执行-print动作,即打印当前测试文件(比如,bers文件)

  • 示例2

按名查找并排除指定目录

figure 9.png

-a、-o 优先级

如前文所述,-a 与操作符优先级高于 -o 或操作符优先级。所以如果不注意这点,很容易会产生Bug。例如,我们期望找到名为 bers 或 numbers.txt 文件,代码如下:

figure-10.png

从上文执行的结果,可以看到没有成功查找出bers文件,原因很简单,由于 -a 优先级比 -o 高,-print 动作只会在-iname ‘numbers.txt’ 测试条件返回true时执行。所以上述命令等价于下图所示

figure-11.png

同理,即使将numbers.txt换为一个不存在的文件名 abc ,也同样不会输出存在的bers文件

figure-12.png

所以,对于该问题,需要通过添加括号来改变操作符的默认优先级,使其满足我们的需求

figure 13.png

0%