【发布时间】:2013-04-29 15:34:30
【问题描述】:
给定一个目录,我如何找到其中所有非硬链接文件的文件(以及任何子目录)?或者更具体地说,那些不是具有多个引用的硬链接文件?
基本上我想扫描一个文件夹并返回该目录中唯一文件的列表,包括目录和符号链接(不是它们的目标)。如果可能,最好也忽略支持它们的文件系统上的硬链接目录(例如 HFS+)。
【问题讨论】:
给定一个目录,我如何找到其中所有非硬链接文件的文件(以及任何子目录)?或者更具体地说,那些不是具有多个引用的硬链接文件?
基本上我想扫描一个文件夹并返回该目录中唯一文件的列表,包括目录和符号链接(不是它们的目标)。如果可能,最好也忽略支持它们的文件系统上的硬链接目录(例如 HFS+)。
【问题讨论】:
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...
硬链接文件具有相同的 inode。您可以使用stat 打印inode 和文件名,并使用awk 仅在inode 第一次出现时打印文件:
stat -c '%i %n' *csv | awk '!seen[$1]++' | cut -d ' ' -f 2-
【讨论】:
我相信您知道,所有文件至少有一个硬链接(在父目录中)。
要回答第一段中的问题(查找没有附加 硬链接的文件),您需要区分目录和其他所有内容。假设你有 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'
(如果任何文件名包含换行符,这仍然会导致问题,这实际上是合法的。)
【讨论】:
所以你想要的是任何文件/链接/目录/块/管道/...但是具有不同的 inode ? 然后很简单,用 inode 列出它们,进行数字排序,最后只打印具有不同 inode 编号的那个......并提醒 find 如果你想过滤,有很多选项可以限制输出
找到 /PATH_to_SEARCH -ls |排序-n | awk '!seen[$1]++'
【讨论】: