查找和符号链接

查找和符号链接

我浏览了 find 的文档以更好地利用命令用法。

我正在读的部分说

GNU find 将以两种方式之一处理符号链接;首先,它可以为您取消引用链接 - 这意味着如果遇到符号链接,它会检查该链接指向的文件,以查看它是否符合您指定的条件。其次,它可以检查链接本身,以防您正在寻找实际的链接。如果符号链接指向的文件也在您使用 find 命令搜索的目录层次结构内,则您可能看不到这两个替代方案之间有很大差异。

默认情况下,find 在找到符号链接时会自行检查它们(并且,如果稍后遇到链接到的文件,它也会检查该链接)。

据我了解,如果我做类似的事情:

find -L -iname "*foo*"

这将递归搜索当前目录,当遇到符号链接时,它会沿着原始文件的链接进行搜索。如果原始文件的名称为pattern *foo*,则报告前一个链接。

然而,情况似乎并非如此。我有

main-file
sl-file -> main-file

运行上面的命令find -L -iname "*main*"会报告

./main-file

我期待着

./main-file # because it matches the criterion
./sl-file   # because the file points to matches the criterion

话虽这么说,使用另一个测试就像-type我所期望的那样。假设我有这个:

main-file
dir/sl-file -> ../main-file

运行这个

find dir -type f

什么也不返回。但是这个

find -L dir -type f

报道dir/sl-file

是什么赋予了?

我已经经历过这个帖子这说明文件名不是文件属性。这是我实在无法理解的事情。

答案1

Gnufind文档在术语上并不像POSIX一。后者阐明了这一点,我将参考它。它没有定义-iname,所以我将专注于-name.我认为-iname它的设计类似于-name,只是不区分大小写。因此,我希望它的所有属性也-name与适用的情况无关。-iname

这些是 POSIX 文档的相关部分:

find [-H|-L] path... [operand_expression...]
find实用程序应从path[…] 指定的每个文件递归地降低目录层次结构。每个path操作数应在提供时按原样进行评估,包括所有尾随 <slash> 字符;层次结构中遇到的其他文件的所有路径名应由当前路径操作数、<slash>(如果当前路径操作数不以 1 结尾)以及相对于路径操作数的文件名的串联组成。相对部分不应包含点或点-点组件,不应包含尾随 <slash> 字符,路径名组件之间仅应包含单个 <slash> 字符。

-name pattern
如果当前路径名的基本名pattern使用模式匹配符号 [...]匹配,则主项应评估为 true

-print
[...]它将导致当前路径名被写入标准输出。

定义:

基本名称
对于至少包含一个文件名的路径名:路径名中的最后一个或唯一一个文件名。 […]

文件名
用于命名文件的字节序列 [...]。组成名称的字节不得包含 <NUL> 或 <slash> 字符。 [...] 文件名有时被称为“路径名组件”。 […]

路径名
用于标识文件的字符串。 [...] 它具有可选的开头 <slash> 字符,后跟零个或多个由 <slash> 字符分隔的文件名。

所以-name对当前路径名中的最终文件名感兴趣;当前路径名是一个字符串,用于标识当前文件。被谁使用?在这种情况下,通过find.从概念上讲,路径名可能与文件系统中的名称无关。如果find使用某个字符串来标识文件,则该字符串称为“路径名”并-name使用它。

调用find . -printfind -L . -print.您将看到此特定调用使用的所有路径名find。如果-name您使用-name.


main-file在您使用and 的示例中sl-file,命令是find -L -iname "*main*"-print最后有隐式,您观察到的输出来自-print.您期望:

./main-file # because it matches the criterion
./sl-file   # because the file points to matches the criterion

但如果是这种情况,则意味着-print给了您./main-file./sl-file,因此这些是确切的路径名,因此main-file和是处理的sl-file相应基名-name(或)。-iname

这不合适。这些基本名称中只有一个与您使用的模式 ( *main*) 匹配。这就是为什么您只得到一个结果。指定-name "*main*"(或-iname "*main*") 并期望./sl-file出现相当于期望sl-file匹配*main*

这将使一些感觉预计./main-file会出现两次。前提是符号链接导致find将第二个路径名从 更改./sl-file./main-file。然后两个路径名都会匹配*main*,并且都将打印为./main-file.这不会发生。

如果您希望发生这种情况,请考虑bar指向/etc/fstab并放置在 中的符号链接/tmp/foo/。我们在foo目录中。应该find -L .打印什么(除了.)?看来您希望此路径名通过-name fstab测试,因此基本名称必须是fstab.另一方面,根据规则,路径名必须以./(因为.是提供的路径)开头,并且不应包含点组成部分。没有可以使用的理智且有意义的路径名。怎么办?幸运的是,在这种情况下,该工具仅打印./bar.这是路径名,它(作为字符串)与fstab.


几个不使用符号链接但展示其-name工作原理的示例:

  1. cd /etc && find . -name . 2>/dev/null

    尽管事实上.它的“真实”(特定的,在文件系统中)名称是etc.尽管在某些情况下任何目录都可以存在,但它找不到子目录.

  2. cd /etc && find . -name etc 2>/dev/null

    它既找不到etc也没有.

  3. 创建一个空的 FAT32 文件系统并将其安装cd到安装点。文件系统不区分大小写,Linux 知道这一点。创建一个a在文件系统中命名的文件。像这样进行实验:

    • $ find .
      .
      ./a

      a在这种情况下,该工具必须在某个时刻从文件系统获取。

    • $ find a
      a
      $ find A
      A

      在这种情况下,该工具使用aA取自其命令行参数。文件系统仅确认此类文件存在。文件系统(和操作系统)知道这个特定文件可以称为aA

    • $ find a -name A
      $ find A -name a

      没有什么!这表明-name并不关心文件系统对文件的了解。只有所使用的路径名才find重要。

      在您的示例中有些类似:-iname不关心文件系统对符号链接及其目标的了解。只有所使用的路径名才find重要。


为了澄清并明确说明发生的情况,让我们回到具有以下目录结构的示例:

.
├── main-file
└── sl-file -> main-file

find . -printfind -L . -print打印:

.
./main-file
./sl-file

这些是路径名,即字符串 find用于识别三者文件(目录也是一个文件)。字符串.来自命令,另外两个是通过检查.(现在我的意思是文件,而不是字符串)构建的,了解它是目录类型,决定我们是否应该下降(一般认为-prune-maxdepth如果支持的话),列出其内容:main-file, sl-file.

请注意,该字符串/.sl-file是在对其标识的文件执行任何操作之前构建的。要对文件执行任何操作,find需要该字符串。

但是-name或者-print不对文件执行任何操作,他们不需要其数据或元数据。他们使用路径名,细绳

-name "*main*"对任何路径名进行评估时,相应的文件或整个文件系统是完全不相关的。唯一相关的是路径名,它是细绳;更具体地说,它的最后一个组成部分,即基本名称,也是细绳

对于任何给定的路径名​​,-name并不关心您是否使用过-L,或者文件是否首先是符号链接,或者它指向哪里,或者它是否没有损坏。它与已知的细绳

另一方面,类似-type-mtime需要查询文件系统的测试文件由路径名标识。字符串对他们来说还不够。如果是符号链接,则-L决定是否查询符号链接的目标或符号链接本身。不过,如果涉及-print的话,无论查询什么,它都会打印路径名。

换句话说:

  • 没有-L

    • ./main-file 细绳识别./main-file 文件类型的f
    • ./sl-file 细绳识别./sl-file 文件类型的l
  • -L

    • ./main-file 细绳识别./main-file 文件类型的f
    • ./sl-file 细绳还确定了./main-file 文件类型的f

然后您应该注意哪个测试或操作适用于路径名(字符串)以及哪个测试或操作适用于文件。

-name-print使用路径名,因此find . -name "*main*"with 或 without-L只会打印

./main-file

-type适用于文件,因此find . -type f将打印一个路径名:

./main-file

并将find -L . -type f打印两个路径名:

./main-file
./sl-file

相关内容