【问题标题】:Finding files that are *not* hard links via a shell script通过 shell 脚本查找不是*硬链接的文件
【发布时间】:2013-04-29 15:34:30
【问题描述】:

给定一个目录,我如何找到其中所有硬链接文件的文件(以及任何子目录)?或者更具体地说,那些不是具有多个引用的硬链接文件?

基本上我想扫描一个文件夹并返回该目录中唯一文件的列表,包括目录和符号链接(不是它们的目标)。如果可能,最好也忽略支持它们的文件系统上的硬链接目录(例如 HFS+)。

【问题讨论】:

    标签: shell hardlink


    【解决方案1】:

    find 有一个应该有用的选项:

    find . -type f -links 1 -print
    

    根据定义硬链接的文件的链接计数为 2 或更大,因此这将显示所有没有其他链接的文件。

    【讨论】:

    • -type f 不包括符号链接、目录和其他一些东西。 OP 特别希望包含目录和符号链接。目录至少有两个硬链接(一个来自父目录,加上目录自己的. 链接),加上每个子目录的.. 一个。
    • -type f 在这种情况下可以省略。但是,问题的第一段和第二段似乎不同意这一要求。通常,目录和符号链接无论如何都不会有硬链接(尽管有一些文件系统类型不如其他类型)。
    • 目录总是有硬链接。他们可以在一些系统上拥有不同于通常的硬链接(来自父目录,.来自目录本身,..来自子目录); OP特别提到了这一点。并且您可以拥有指向符号链接的硬链接:touch file; ln -s symlink file; ln hardlink symlink 将使 hardlink 成为指向 file 的符号链接,其 inode 编号与 symlink 相同。
    • 对 - 我的意思不是“通常”,因为硬链接符号链接并不是一种特别常见的做法(以及我能想到的任何实际情况)有用是相当做作的)。而且,是的,目录使用硬链接计数的目的略有不同——但实际上你通常不能使用ln dir1 dir2...
    【解决方案2】:

    硬链接文件具有相同的 inode。您可以使用stat 打印inode 和文件名,并使用awk 仅在inode 第一次出现时打印文件:

    stat -c '%i %n' *csv | awk '!seen[$1]++' | cut -d ' ' -f 2-
    

    【讨论】:

    • 感谢您的回复!这是我要采用的解决方案,但存在一些差异;我正在获取一个目录中文件的 inode 编号,并与前一个目录中的相应文件进行比较,如果它们匹配,则我跳过它,否则它没有链接。这也适用于硬链接目录(在支持的文件系统上)。
    【解决方案3】:

    我相信您知道,所有文件至少有一个硬链接(在父目录中)。

    要回答第一段中的问题(查找没有附加 硬链接的文件),您需要区分目录和其他所有内容。假设你有 GNU Coreutils,你可以使用:

    stat '%h' filename
    

    确定给定文件名的硬链接数。否则,您可以解析 ls -ld filename 的输出——这应该可以工作,但 ls 的输出并不意味着机器可读。

    对于目录以外的任何内容,如果链接数大于 1,则在某处存在指向它的硬链接。

    另一方面,目录将始终具有来自其父级的通常的一个链接,加上一个用于其自己的. 条目,再加上一个用于每个.. 条目它的直接子目录。因此,您必须确定在没有任何其他硬链接的情况下它会有多少链接,并将其与实际拥有的数量进行比较。

    如果您碰巧知道您使用的是禁止硬链接到目录的系统,则可以避免这样做。 (我不确定该限制通常是由操作系统还是由每个文件系统施加的。)

    但这并不能解决第二段中的问题,即在目录中创建唯一文件列表。知道普通文件 foo 的链接数大于 1 告诉您它在当前目录中是否唯一;其他硬链接可以在不同的目录中(它们只需要在同一个文件系统中)。

    为此,您可以执行以下操作:

    stat -c '%i %n' *
    

    打印当前目录中每个文件的 inode 编号和名称。然后,您可以过滤掉重复的 inode 编号以获得唯一条目。这基本上就是glenn jackman's answer 所说的。当然* 实际上并不匹配当前目录中的everything;它会跳过名称以. 开头的文件,如果某些文件的名称中包含特殊字符(如空格),则可能会导致问题。这对您来说可能无关紧要,但如果确实如此(假设 GNU 找到):

    find . -maxdepth 1 -print0 | xargs -0 stat -c '%i %n'
    

    (如果任何文件名包含换行符,这仍然会导致问题,这实际上是合法的。)

    【讨论】:

    • 感谢您的详细回复!如果有帮助,我实际上要做的是在 OS X 上递归 Time Machine 备份目录,并希望过滤掉所有只是指向先前备份的链接的内容。对于文件,这应该意味着任何只有 1 个链接的东西就足够了,但对于目录,我可能不得不使用更棘手的东西。
    • find 知道 inode 编号并可以直接打印它们,而无需通过管道输入 xargs: find 。 -maxdepth 1 -printf "%i %p\n"
    【解决方案4】:

    所以你想要的是任何文件/链接/目录/块/管道/...但是具有不同的 inode ? 然后很简单,用 inode 列出它们,进行数字排序,最后只打印具有不同 inode 编号的那个......并提醒 find 如果你想过滤,有很多选项可以限制输出

    找到 /PATH_to_SEARCH -ls |排序-n | awk '!seen[$1]++'

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多