GNU find -not 和 GNU find -prune -o -print 之间的区别

Yor*_*rov 2 find gnu dot-files file-search syntax

关于在 vim 中打开除 [condition] 之外的所有文件的答案:

https://unix.stackexchange.com/a/149356/98426

给出了类似的答案:

find . \( -name '.?*' -prune \) -o -type f -print

(我修改了答案,因为我在这里的问题与 vim 无关)

其中否定条件位于转义括号中。但是,在我的测试文件中,以下内容

find . -type f -not -name '^.*'

产生相同的结果,但更易于读写。-not 方法与 -prune 方法一样,会修剪任何以 . (点)。我想知道 -not 和 -prune -o -print 方法会产生不同结果的边缘情况是什么。

Findutils 的信息页面如下:

-not expr : 如果 expr 为假则为真

-prune:如果文件是目录,则不下降到其中。(并进一步说明需要 -o -print 才能实际排除顶级匹配目录)

他们似乎很难以这种方式进行比较,因为 -not 是一个测试,而 -prune 是一个动作,但对我来说,它们是可以互换的(只要 -o -print 出现在 -prune 之后)

Sté*_*las 6

首先,请注意这-not是一个 GNU 扩展,相当于标准!运算符。它几乎没有任何优势!

-prune谓词总是为,并影响了道路find行走目录树。如果该文件为这-prune是运行的类型的目录(具有可能的符号链接后分辨率确定-L/ -H/ -follow,然后)find将不会下降到它。

所以-name 'pattern' -prune(简称-name 'pattern' -a -prune)与-name 'pattern'除了名称匹配的目录pattern将被修剪外相同,即find不会下降到它们中。

-name '.?*'匹配名称开头.后跟一个字符(其定义取决于当前语言环境)后跟 0 个或多个字符的文件。所以实际上,匹配.后跟一个或多个字符(以免修剪.起始目录)。

因此,匹配隐藏文件,但需要注意的是,它仅匹配名称也完全由characters 组成的文件,即当前语言环境中的有效文本(至少在 GNU 实现中)。

所以在这里,

find . \( -name '.?*' -a -prune \) -o -type f -a -print
Run Code Online (Sandbox Code Playgroud)

这与

find . -name '.?*' -prune -o -type f -print
Run Code Online (Sandbox Code Playgroud)

因为 AND ( -a, 隐含) 优先于 OR ( -o)。

查找常规文件(无符号链接、目录、fifo、设备...)且未隐藏且不在隐藏目录中(假设所有文件路径都是区域设置中的有效文本)。

find . -type f -not -name '^.*'
Run Code Online (Sandbox Code Playgroud)

或者它的标准等价物:

find . -type f ! -name '^.*'
Run Code Online (Sandbox Code Playgroud)

会找到名称不以^..

find . -type f ! -name '.*'
Run Code Online (Sandbox Code Playgroud)

会找到名称不以 开头的常规文件.,但仍会报告隐藏目录中的文件。

find . -type f ! -path '*/.*'
Run Code Online (Sandbox Code Playgroud)

将省略隐藏文件和隐藏目录中的文件,但find仍会下降到隐藏目录(任何深度)只是为了跳过其中的所有文件,因此效率低于使用-prune.


Kus*_*nda 5

-prune谓词find删除搜索树的一个分支。因此,-prune 如果目录中没有具有隐藏名称的文件,则在问题中的第一个命令中使用as 只会为您提供与第二个命令相同的结果。

例子:

$ tree -a
.
|-- .hiddendir
|   `-- file
`-- dir
    `-- file

2 directories, 2 files
Run Code Online (Sandbox Code Playgroud)
$ find . \( -name '.?*' -prune \) -o -type f -print
./dir/file
Run Code Online (Sandbox Code Playgroud)
$ find . -type f ! -name '.*'
./dir/file
./.hiddendir/file
Run Code Online (Sandbox Code Playgroud)

(我更正了-name这里的测试,因为您似乎使用了无意义的正则表达式,并且我使用!了非标准的-not)。

如您所见,由于名称.hiddendir与 globbing 模式匹配.?*,因此使用第一个命令将其从搜索树中删除,并且file找不到它下面的文件。

在第二个命令中,.hiddendir没有从搜索树中修剪目录,因此file找到了其中的文件。