Linux技巧:find 命令简单入门介绍和问题点解析( 三 )


具体举例说明如下:
$ find . -path ./tests./tests$ find . -path tests$ find . -path ./tests/$ find teststeststests/bre.tests$ find tests -path teststests$ find tests -path ./tests可以看到,find . -path ./tests 命令打印了 ./tests 目录名,但是 find . -path tests 命令什么都没有打印 。
查看上面 find . 命令打印的信息,可以看到该命令打印的 tests 目录名是 ./tests,-path 参数要求是完全匹配才会返回 true,所以基于打印结果,就是要写为 -path ./tests 才会返回 true 。
【Linux技巧:find 命令简单入门介绍和问题点解析】前面贴出的 man find 说明提到,没有提供除了 -prune 表达式之外的其他 action 类型表达式时,默认会对所有返回 true 的文件名执行 -print 表达式,打印该文件名 。
所以打印结果里面只有匹配到的 ./tests 目录名,那些没有完全匹配 ./tests 的文件名会返回 false,没有被打印 。
由于 find . 命令打印的目录名后面没有加上 / 字符,所以 find . -path ./tests/ 也匹配不到任何文件名,没有打印任何信息 。
类似的,执行 find tests 命令,打印的 tests 目录名是 tests,那么 find tests -path tests 命令可以完全匹配 tests 模式,打印出这个目录名 。
而 find tests -path ./tests 就匹配不到,没有打印 。
即,根据传入的目录参数不同,find 打印的目录名不同,-path 后面要提供的目录名也不同 。
总的来说,在 -path 后面跟着的目录名,需要完全匹配 find 命令打印的目录名,而不是部分匹配 。如果不确定 find 命令打印的目录名是什么,可以先不加 -path 参数执行一次 find 命令,看打印的文件名是什么,再把对应的文件名写到 -path 参数后面 。
在 -path 后面的 pattern 模式可以用通配符匹配特定模式的文件名,常见的通配符是用 * 来匹配零个或多个字符 。
在 find 中使用时有一些需要注意的地方,举例说明如下:
$ find . -path *test*$ find . -path ./test*./tests$ find . -path *test*./tests./tests/bre.tests$ find . -path "*test*"./tests./tests/bre.tests可以看到,find . -path *test* 什么都没有打印,*test* 没有匹配到 ./tests 这个名称 。
原因是这里的 * 通配符是由 bash 来处理,通过文件名扩展来得到当前目录下的子目录名或者文件名,但是不会在目录名前面加上 ./ 。
即,这里的 find . -path *test* 相当于 find . -path tests,前面已经说明这是不匹配的 。
find . -path ./test* 可以打印出匹配到的目录名,经过 bash 扩展后,这个命令相当于 find . -path ./tests 。
find . -path *test* 命令不但匹配到了 ./tests 目录,还匹配到了该目录下的 ./tests/bre.tests 文件 。
这里用 * 对 * 进行转义,对 bash 来说它不再是通配符,不做扩展处理,而是把 * 这个字符传递给 find 命令,由 find 命令自身进行通配符处理,可以匹配到更多的文件 。
这里面涉及到 bash 和 find 对 * 通配符扩展的区别,bash 在文件名扩展 * 时,遇到斜线字符 / 则停止,不会扩展到目录底下的文件名 。
而 find 没有把 / 当成特殊字符,会继续扩展到目录底下的文件名 。
查看 GNU find 在线帮助手册 https://www.gnu.org/software/findutils/manual/html_mono/find.html#Shell-Pattern-Matching 的说明如下:

Slash characters have no special significance in the shell pattern matching that find and locate do, unlike in the shell, in which wildcards do not match them.
find . -path "*test*" 命令的打印结果跟 find . -path *test* 相同 。
原因是,bash 没有把双引号内的 * 当成通配符,会传递这个字符给 find,由 find 来处理通配符扩展 。
如果不想用 * 来转义,可以用双引号把模式字符串括起来 。
注意:虽然 -path 表达式的名字看起来是对应目录路径,但是也能用于匹配文件名,并不只限于目录 。
在 man find 里面提到,有一个 -wholename 表达式和 -path 表达式是等效的,但是只有 GNU find 命令支持 -wholename 表达式,其他版本的 find 命令不支持该表达式 。从名字上来说,-wholename 表达式比较准确地表达出要完全匹配文件名称 。
-and这是一个 operator 操作符,GNU find 在线帮助手册对该操作符的说明如下:
expr1 expr2
expr1 -a expr2
expr1 -and expr2
And; expr2 is not evaluated if expr1 is false.
可以看到,-and 操作符有三个不同的写法,都是等效的 。
find 命令的操作符把多个表达式组合到一起,成为一个新的组合表达式,组合表达式也会有自身的返回值 。


推荐阅读