zzr*_*zzr 218

您可以使用以下命令找到文件的 inode 编号

ls -i
Run Code Online (Sandbox Code Playgroud)

ls -l
Run Code Online (Sandbox Code Playgroud)

显示引用计数(特定 inode 的硬链接数)

找到 inode 编号后,您可以搜索所有具有相同 inode 的文件:

find . -inum NUM
Run Code Online (Sandbox Code Playgroud)

将在当前目录 (.) 中显示 inode NUM 的文件名

  • 你可以运行 find 。-samefile 文件名 (65认同)
  • @BeowulfNode42这个命令很棒,但它至少需要相同文件的共享根文件夹。 (2认同)
  • 这个答案给出了一个务实的“这样做”,但我强烈认为 [@LaurenceGonsalves 回答](http://superuser.com/a/12973/28756) 是“如何”和/或“为什么”的问题。 (2认同)

Lau*_*ves 73

对于您的问题,并没有真正明确的答案。与符号链接不同,硬链接与“原始文件”无法区分。

目录条目由文件名和指向 inode 的指针组成。inode 又包含文件元数据和(指向)实际文件内容的指针)。创建硬链接会创建另一个引用相同 inode 的目录条目。这些引用是单向的(至少在典型的文件系统中)——inode 只保留一个引用计数。没有内在的方法可以找出哪个是“原始”文件名。

顺便说一下,这就是“删除”文件的系统调用被称为unlink. 它只是删除了硬链接。仅当 inode 的引用计数降至 0 时,才会删除 inode 和附加数据。

找到对给定 inode 的其他引用的唯一方法是彻底搜索文件系统,检查哪些文件引用了有问题的 inode。您可以使用 shell 中的“test A -ef B”来执行此检查。

  • 这意味着*不存在到另一个文件的硬链接*,因为原始文件也是一个硬链接;硬链接指向*磁盘上的位置*。 (39认同)
  • @jtbandes:硬链接指向一个指向实际数据的 inode。 (12认同)
  • @jtbandes 不要尝试将硬链接弯曲到另一个文件系统位置,这是不可能的。相反,尝试认识到事实,即不存在到另一个文件系统位置的硬链接。然后你就会发现,弯曲的不是链接,而是你自己。另一方面,如果链接是象征性的,那么它实际上只是一个勺子。 (3认同)

小智 35

UNIX 有硬链接和符号链接(分别由"ln""ln -s"组成)。符号链接只是一个包含另一个文件的真实路径的文件,可以跨越文件系统。

硬链接从 UNIX 的早期就已经存在(无论如何我都记得,而且可以追溯到很长一段时间)。它们是引用完全相同的基础数据的两个目录条目。文件中的数据由其inode. 文件系统上的每个文件都指向一个 inode,但不要求每个文件都指向一个唯一的 inode——这就是硬链接的来源。

由于 inode 仅对于给定的文件系统是唯一的,因此存在硬链接必须位于同一文件系统上的限制(与符号链接不同)。请注意,与符号链接不同,没有特权文件 - 它们都是平等的。只有当所有使用该 inode 的文件都被删除(并且所有进程也将其关闭,但这是一个不同的问题)时,才会释放数据区。

您可以使用该"ls -i"命令来获取特定文件的 inode。然后,您可以使用该"find <filesystemroot> -inum <inode>"命令查找文件系统上具有给定 inode 的所有文件。

这是一个完全可以做到这一点的脚本。你调用它:

findhardlinks ~/jquery.js
Run Code Online (Sandbox Code Playgroud)

它将找到该文件系统上的所有文件,这些文件是该文件的硬链接:

pax@daemonspawn:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
   '/home/pax/jquery.js' has inode 5211995 on mount point '/'
       /home/common/jquery-1.2.6.min.js
       /home/pax/jquery.js
Run Code Online (Sandbox Code Playgroud)

这是脚本。

#!/bin/bash
if [[ $# -lt 1 ]] ; then
    echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
    exit 1
fi

while [[ $# -ge 1 ]] ; do
    echo "Processing '$1'"
    if [[ ! -r "$1" ]] ; then
        echo "   '$1' is not accessible"
    else
        numlinks=$(ls -ld "$1" | awk '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done
Run Code Online (Sandbox Code Playgroud)

  • @Masi 问题是您的初始 . (与源命令相同)。这会导致 exit 1 命令退出您的 shell。使用 chmod a+x findhardlinks.bash 然后使用 ./findhardlinks.bash 或使用 bash findhardlinks.bash 执行它 (4认同)
  • 要以编程方式执行此操作,如果您改为使用它,它可能更具弹性:`INUM=$(stat -c %i $1)`。还有`NUM_LINKS=$(stat -c %h $1)`。有关您可以使用的更多格式变量,请参阅“man stat”。 (3认同)

小智 30

ls -l
Run Code Online (Sandbox Code Playgroud)

第一列将代表权限。第二列将是子项的数量(对于目录)或到文件的相同数据(硬链接,包括原始文件)的路径数量。例如:

-rw-r--r--@    2    [username]    [group]    [timestamp]     HardLink
-rw-r--r--@    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
Run Code Online (Sandbox Code Playgroud)

  • 有助于确定给定文件是否有 [其他] 硬链接,但不知道它们在哪里。 (4认同)

Lov*_*ity 15

下面这个更简单的怎么样?(后者可能会取代上面的长脚本!)

如果您有一个特定的文件<THEFILENAME>并且想知道它分布在目录中的所有硬链接<TARGETDIR>,(甚至可以是整个文件系统,用 表示/

find <TARGETDIR> -type f -samefile  <THEFILENAME>
Run Code Online (Sandbox Code Playgroud)

扩展逻辑,如果您想知道<SOURCEDIR>分布在多个硬链接中的所有文件<TARGETDIR>

find <SOURCEDIR> -type f -links +1   \
  -printf "\n\n %n HardLinks of file : %H/%f  \n"   \
  -exec find <TARGETDIR> -type f -samefile {} \; 
Run Code Online (Sandbox Code Playgroud)

  • @silvio:您只能创建到 _files_ 的硬链接,而不是目录。 (3认同)

Pet*_*des 9

有很多脚本可以找到文件系统中的所有硬链接。他们中的大多数人都会做一些愚蠢的事情,例如运行 find 来扫描整个文件系统以-samefile查找每个多链接文件。这太疯狂了; 您所需要的只是对 inode 编号进行排序并打印重复项。

只需通过文件系统一次即可查找和分组所有硬链接文件集

find dirs   -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
    sort -n | uniq -w 42 --all-repeated=separate
Run Code Online (Sandbox Code Playgroud)

这比查找多组硬链接文件的其他答案要快得多。
find /foo -samefile /bar仅适用于一个文件。

  • -xdev: 限制为一个文件系统。并非严格需要,因为我们还将 FS-id 打印到 uniq
  • ! -type d拒绝目录:...条目意味着它们始终是链接的。
  • -links +1 : 链接数严格 > 1
  • -printf ...打印 FS-id、inode 号和路径。(填充到固定的列宽,我们可以知道uniq。)
  • sort -n | uniq ... 对前 42 列进行数字排序和统一,用空行分隔组

Using! -type d -links +1意味着 sort 的输入仅与 uniq 的最终输出一样大,因此我们不会进行大量的字符串排序。除非您在仅包含一组硬链接之一的子目录上运行它。无论如何,这将比任何其他发布的解决方案使用更少的 CPU 时间来重新遍历文件系统。

示例输出:

...
            2429             76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
            2429             76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar

            2430             17961006 /usr/bin/pkg-config.real
            2430             17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config

            2430             36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...
Run Code Online (Sandbox Code Playgroud)

TODO?: 用awk或取消填充输出cutuniq对字段选择的支持非常有限,所以我填充 find 输出并使用固定宽度。对于最大可能的 inode 或设备号 (2^64-1 = 18446744073709551615),20 个字符足够宽。XFS 根据它们在磁盘上分配的位置来选择 inode 编号,而不是从 0 开始连续选择,因此即使没有数十亿个文件,大型 XFS 文件系统也可以具有 >32 位的 inode 编号。其他文件系统可能有 20 位 inode 编号,即使它们不是很大。

TODO:按路径对重复组进行排序。如果你有几个不同的子目录有很多硬链接,让它们按挂载点排序,然后 inode 编号会将事情混合在一起。(即 dup-groups 组在一起,但输出将它们混合在一起)。

finalsort -k 3将分别对行进行排序,而不是将行组作为单个记录进行排序。用一些东西预处理将一​​对换行符转换为 NUL 字节,并使用 GNUsort --zero-terminated -k 3可能会成功。 tr但是,仅对单个字符进行操作,而不是 2->1 或 1->2 模式。 perl会这样做(或者只是在 perl 或 awk 中解析和排序)。 sed也可能工作。

  • `%D` 是文件系统标识符(它对于当前启动来说是唯一的,而没有文件系统被`umount`ed),因此以下内容更加通用:`finddirectories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' |排序 -n | uniq -w 42 --all-repeated=单独`。只要给定目录不包含文件系统级别的另一个目录,它就会起作用,并且它还会查看可以硬链接的所有内容(例如设备或软链接 - 是的,软链接的链接计数可以大于 1)。请注意,现在 `dev_t` 和 `ino_t` 的长度是 64 位。只要我们有 64 位系统,这种情况就可能持续下去。 (2认同)