如何在文件夹中找到所有的硬链接?

我有两个外部硬盘,它们有相同的文件。其中一个是加密的,另一个没有加密。加密的那个剩余空间比未加密的要少很多,我现在猜测这是因为未加密硬盘上存在硬链接。
所以我想检查一下,加密硬盘上是否存在可能重复的硬链接文件。如何识别硬链接呢?
如果你对剩余空间问题的原因有其他想法,我愿意听取。文件因为加密而需要更多空间,这种可能性存在吗?

请在原问题中进行编辑,当两个外部磁盘连接并且它们的分区被挂载时,请展示以下命令对于两个文件系统(加密和未加密)的输出:dfsudo lsblk -fsudo lsblk -m;每行缩进4个空格以将输出呈现为code - sudodus
4个回答

$ find -type f -links +1

这将显示所有具有多个链接(名称)的常规文件。它不会告诉您哪些名称链接到同一个文件,对于此,您可以使用-samefile-inum,例如find -samefile "$somefile"

从技术角度来说,所有文件(文件名)都是(硬)链接,只是具有多个链接指向它们的文件在这个意义上更有趣。但即使在这些情况下,也无法说其中一个是“正确”的文件,而另一个是链接,这些链接是相等的。

以一个例子来说明:

$ touch a b c
$ ln b b2 ; ln c c2
$ find -type f -links +1
./c2
./b
./b2
./c
$ find -samefile b
./b
./b2

+1 这是一个很好的回答 :-) 我会借鉴它来写我的回答。 - sudodus
1-links +1是GNU的扩展功能。为了更好的可移植性(符合POSIX标准),请使用等效的\! -links 1,例如:find . -type f \! -links 1。此外,-samefile同样是GNU的扩展功能,在find命令中没有简单的POSIX等效方式(至少目前还没有)。 - Wildcard
@Wildcard,是的。虽然我还没有见过一个非GNU用户空间的Ubuntu系统。 - ilkkachu
啊,那是真的。我经常上Unix & Linux SE,往往忘记在这里可移植性不是那么重要。 :) - Wildcard

搜索硬链接

@ilkkachu和@barrycarter的答案都很好。这个答案是一个替代方案,更详细地描述了一些结果。

如果链接的匹配项在同一目录树中,您将直接找到它们。
否则,您可以从挂载点在整个文件系统中搜索,但仅限于相同的文件系统,使用-xdev选项非常重要,特别是当您搜索根分区/并存在其他已挂载的分区时。 $ sudo find / -xdev -type f -links +1 -ls | sort -n > hard-links-in-root.txt
以下是一个例子,在当前目录中找到了一个硬链接对,通过从数据分区的挂载点/media/multimed-2进行搜索,在另一个目录中找到了两个硬链接匹配项。
$ sudo find . -xdev -type f -links +1 -ls | sort -n
  5242881    648 -rw-rw-r--   2 olle     nio        657936 jun 30  2015 ./like-this.png
  5242882    940 -rw-rw-r--   2 olle     nio        957688 jun 30  2015 ./from-here.png
 14843905   1620 -rw-r--r--   2 olle     nio       1652803 jun 30  2015 ./img_4810.jpg
 14843905   1620 -rw-r--r--   2 olle     nio       1652803 jun 30  2015 ./mid-sommer-night_4810.jpg

$ find /media/multimed-2/ -samefile ./like-this.png
/media/multimed-2/Photos/2015/06/30/like-this.png
/media/multimed-2/Bilder/kartor/like-this.png

$ find /media/multimed-2/ -samefile ./from-here.png
/media/multimed-2/Photos/2015/06/30/from-here.png
/media/multimed-2/Bilder/kartor/from-here.png

其他导致使用不同磁盘空间的原因

  • 不同的文件系统(ext4、NTFS、FAT32等)

  • 不同的分区大小,导致开销(元数据)的差异。

  • 驱动器上的扇区大小可能不同。


理论上,硬链接应该与普通文件无法区分(这是它的目的)。如果“x”是指向“y”的硬链接,那么“y”也是指向“x”的硬链接。话虽如此,ls -l命令的第二列告诉你有多少个链接指向某个文件。如果这个数字大于1,那么该文件就是一个硬链接或者存在一个硬链接。这对于目录可能不适用,但我不确定原因。最初我说每个目录中的文件都有一个链接指向该目录,但我错了:我找到了一个只有2个“链接计数”的目录,其中包含10个文件。

一旦找到了硬链接,你可以使用ls -i命令查看其inode,然后使用find命令的inode选项来查找具有相同inode的其他文件(从而使它们成为彼此的硬链接)。请确保将find命令限制在特定设备上,否则可能会得到虚假结果。

要一次性找到所有硬链接,可以让find命令输出设备上所有文件的inode,然后使用sortuniq等工具来查找重复项。


2这对于目录可能不起作用,但我不确定原因。最初我说每个目录中的文件都有一个指向该目录的链接,但我错了:我发现一个目录有10个文件,其“链接计数”只有2。父目录有一个指向该目录的链接,目录本身有一个指向自己的“.”,每个子目录都有一个指向它的“..”。 - tkausl
3从技术上讲,硬链接只是将文件名与某些数据关联起来。每个普通文件(即非符号链接、设备等)都是一个硬链接。所以我要抱怨一句,"如果这个数字大于1,则该文件是或者在某处有一个硬链接"并不完全准确;我宁愿看到它说"...该文件在其他地方有另一个硬链接"或类似的表达。不过这只是一个小问题。 - David Z
@DavidZ 这虽然是个小问题,但却很重要,因为人们很容易忽视这一事实。原帖的真正需求是一个列出所有非目录且链接计数大于等于2的文件的清单。 - Monty Harder

你可以像这样做: find . -type t -ls | grep -v " 1 username" 这将列出当前目录中的文件并对其执行ls。正如@barrycarter所说,硬链接与真实文件无法区分,但在此列表中,它们将显示为具有多个链接。使用grep -v,您可以筛选出仅具有一个链接的文件。(grep命令中的username是为了使grep在正确的位置查找单个1。请用您自己的用户名替换。)

1事实上,常规的 ls -l 也能显示这一点,而 ls -l | perl -anle 'print $F[1]' 是一个更通用的解决方案(你还可以使用 cut 或其他工具)。我将这一列称为“大家忽略的列” :) 令我惊讶的是,有些软件包/软件会创建硬链接,我原本以为我的驱动器是没有硬链接的,但显然并非如此。 - user11553