硬链接的用例?[关闭]


40

在什么情况下,您想使用硬链接而不是软链接?我个人从未遇到过要在软链接上使用硬链接的情况,并且在搜索Web时遇到的唯一用例是对相同文件进行重复数据删除


4
下面有很好的答案,但请考虑(有争议的)历史背景。当Unix是新的时,磁盘驱动器速度很慢,容量和缓冲都有限。硬链接只是文件系统中指向同一文件的另一个直接条目。无论您访问的是ls还是您喜欢的名称list,都没有关系。如果您使list成为软链接,则其使用将涉及在目录中找到它,读取名为list的特殊文件,查看是否需要ls文件,在目录中找到ls以及从磁盘读取实际的ls文件。性能上的巨大差异!
RichF

16
那么,到文件的第一个硬链接非常有用。
停止Harming Monica

@OrangeDog:是的,但是如果要支持多个链接,则仅需要在inode中有一个链接计数字段。(对于inode的内存版本,您可能需要一个标志来处理未链接但仍处于打开状态的情况。没有日志的崩溃后的fsck仍然必须寻找没有链接的inode。)
Peter Cordes

1
POSIX目录语义必须进行不同的设计:..始终与.父目录中的索引节点相同。诸如此类的操作find可以检查link-count = 2来检测叶目录,并避免stat从readdir中查找条目以查找子目录。但这只是对非目录文件的硬链接(常规,符号链接,设备,套接字和命名管道)的支持而启用的次要功能。(是的,符号链接具有自己的inode,并且可以进行硬链接。)
Peter Cordes

1
我对SO的评论中没有提到使用硬链接的一个原因,这种硬链接具有“全局”性质。想象一下一个文件系统,其中文件通常很小(大多是简短的备忘录),但是要使事情井井有条,您可能需要在不同位置指向同一文件的指针。通过符号链接,每个指针都用完一个索引节点。这样的文件系统可能已经存在索引节点用尽的问题。使用硬链接作为指针可以解决此问题。索引节点数量有限;它们的名称不是(至少不是以相同的方式)。
mathguy

Answers:


27

除了在另一条评论中提到的备份用法(我相信它还包括BTRFS卷上的快照)之外,通过软链接进行硬链接的用例是按标签排序的文件集合。(不一定是创建集合的最佳方法,数据库驱动的方法可能会更好,但是对于一个相当稳定的简单集合来说,还算不错。)

一种媒体收藏,其中所有文件都存储在一个目录中,并根据各种条件(例如,年份,主题,艺术家,流派等)分类到其他目录中。这可以是个人电影收藏,也可以是商业工作室的收藏作品。本质上说,文件被保存,不太可能被修改,并可能通过链接分类到多个位置。

请记住,“原始”和“复制”的概念不适用于硬链接:指向文件的每个链接都是原始链接,正常情况下没有“复制”。但是,对于用例的描述,这些术语模仿行为的逻辑。

“原始”保存在“目录”目录中,排序后的“副本”硬链接到这些文件。可以将排序目录上的文件属性设置为r / o,以防止对文件名和排序结构的任何意外更改,而目录目录上的属性可以是r / w,允许根据需要对其进行修改。(这种情况的例子是音乐文件,其中一些播放器尝试根据用户输入或Internet检索中基于媒体文件中嵌入的标签来重命名和重新组织文件。)此外,由于“复制”目录的属性可能不同于在“原始”目录中,可以对访问权限受限的组或世界提供排序的结构,而主要“目录”只能由主要用户访问,具有完全访问权限。但是,文件本身在指向该索引节点的所有链接上始终具有相同的属性。(可以探索ACL来增强它,但不能增强我的知识领域。)

如果原始文件被重命名或移动(例如,单个“目录”目录变得太大而无法管理),则硬链接仍然有效,软链接断开。如果“副本”被移动并且软链接是相对的,则软链接将再次断开,而硬链接将不会断开。

注意:当涉及软链接时,不同的工具如何报告磁盘使用情况似乎不一致。但是,使用硬链接似乎是一致的。因此,如果将目录中的100个文件分类为“标签”的集合,则很容易就有500个链接的“副本”。(例如,对于一个照片集,例如日期,摄影师,以及平均3个“主题”标签。)例如,海豚会报告为硬链接为100个文件,如果使用软链接为600个文件。有趣的是,它以两种方式报告相同的磁盘空间使用情况,因此对于软链接而言,它看起来像是一大堆小文件,对于硬链接来说,它看起来像一小堆大文件。

这种用例的一个警告是,在使用COW的文件系统中,修改“原始”可能会破坏硬链接,但不会破坏软链接。但是,如果要复制原版,则在编辑,保存和排序后,COW不会进入场景。


3
仅供参考:btrfs快照不是硬链接。它们具有不同的行为(例如,修改一个副本不会修改另一个副本)。并且stat只会显示一个链接。
derobert

@derobert不确定快照的工作方式,很少有调查显示有趣的事情。对于未更改的文件/目录,请stat显示相同的索引节点号,但显示不同的设备ID。必须与子卷叠加在很少安装的主卷上的方式有关。我怀疑如果安装了主卷,则stat链接数量将等于持有该文件版本的快照数量。COW可能会考虑修改一个而不影响其他任何一个。仅仅是基于轻微的好奇心而进行的猜测,但还不足以使人们更深入地了解。
Gypsy Spellweaver

每个符号链接都有其自己的索引节点,因此会用完文件系统中的索引节点条目。传统的Unix文件系统要求您选择在FS创建时为inode保留多少空间,而不是像XFS那样按需分配它。因此,有意义的是,符号链接版本将使用更多的索引节点(甚至不包括VFS缓存占用空间的问题)。
彼得·科德斯

23

硬链接在您不想同时存在两个文件的情况下很有用。考虑一下:

touch a
ln -s a b
rm a

现在b没用了。(这些步骤可能相距很远,可以由不同的人来完成,等等。)

而通过硬链接,

touch a
ln a b
rm a

b 仍然存在并且正确。


8
@MatthewCline在管理有效的增量备份时,您将需要此行为。特别是当删除旧备份时,在基于软链接的备份系统中,您将必须检查所有新的备份文件/链接并将其重新链接到有效的基础上,而硬链接则在inode级别上“免费”完成该工作。例如timeshift / backintime广泛使用硬链接。
orzechow

3
@orzechow我认为您不希望备份系统附近的任何地方发生硬链接行为。github.com/bit-team/backintime/wiki/…backintime愚蠢地认为,对文件的所有更改将是通过remove-create循环完成的,而不是就地进行的。
DepressedDaniel

10
@DepressedDaniel硬链接备份系统中很好用,您只是不希望将备份硬链接到实时文件。但是无论如何,永远都不能直接从实时系统访问备份...
Stephen Kitt

1
这不是答案-具体地说,这不是用例。这只是硬链接行为的演示。
user394

1
@ ThomasPadron-McCarthy真是个误会。BiT仅使用硬链接来链接不同快照中的相同文件。它们未链接到原始文件!(我是BiT开发人员)
Germar

11

单个程序可能会更改其行为,具体取决于它以什么名称启动:

$ ls -li `which pgrep` `which pkill`
208330 -r-xr-xr-x  2 root  bin  19144 Jul 26  2016 /usr/bin/pgrep
208330 -r-xr-xr-x  2 root  bin  19144 Jul 26  2016 /usr/bin/pkill

源中的哪个是通过类似的方式决定的

if (strcmp(__progname, "pgrep") == 0) {
    action = grepact;
    pgrep = 1;
} else {
    action = killact;

尽管确切的细节会随所涉及的操作系统和语言而有所不同。

这允许(大部分)相同的代码不必编译成两个(大部分)相同的二进制文件。请记住,unix可以追溯到磁盘空间非常昂贵的日子,尽管根据Stevens在APUE中的第4章,符号链接是在BSD4.2(1983)中实现的,以替代硬链接的各种限制。用于检查符号链接名称是否用作程序名称的测试程序可能类似于:

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    printf("called as '%s'\n", *argv);
    exit(0);
}

并通过以下方式进行了测试:

$ cc -o myname myname.c 
$ ln -s myname alias
$ ./myname
called as './myname'
$ ./alias
called as './alias'
$ 

4
但这不是通常使用软链接处理的吗?
马修·克莱恩

1
@MatthewCline可能是今天,但是根据APUE中的史蒂文斯的说法,符号链接在4.2BSD(1983)之前就不存在。
thrig

4
@thrig,该问题专门要求使用符号链接无法完成或至少比使用符号链接更好的用例。您的答案适用于HL和SL。
Marcelo

3
BusyBox最大限度地利用了这一点。
马克斯·里德

8

当我的P2P软件完成下载特定文件时,该文件将放置在特定目录中。下载的文件几乎不需要进行编辑。常见的情况是我在需要文件的其他目录中进行了硬链接。

好处:

  • 即使我rm还是mv“副本”,我仍然应该在P2P网络中共享文件。
  • 该文件也位于我需要的路径中;大多数此类位置都不共享。
  • 我可以rm“原始”停止共享文件;此操作不会影响所需位置的“复制”。
  • 我的磁盘空间仅使用了一次。

要点:如果我事先知道rm首先要使用哪个文件,则可以使用symlink。但是我永远不知道。


6

文件系统是一种简单而有效的组织和分类文件的方法(这是它们存在的最主要原因)。硬链接在此问题上具有更高的灵活性。

如前所述,在处理硬链接时没有原始和副本的概念,所有目录条目(硬链接)只是对文件存在的引用(指向其inode的引用),没有优先权,因此也没有损坏的硬链接。 。

因此,这里有一些链接参与包含软链接的用例:

  1. 假设您拥有电影,音乐或其他媒体的集合,并且希望应用不同的分类标准,例如按艺术家在分支中分类的歌曲(每个艺术家都有自己的子目录);依流派在另一个分支中(每个流派都在不同的子目录中),等等。仍然您不希望复制文件,也不想决定将“原始”文件放置在何处,以便您可以自由地进行重新分类而不必“管理”,并在移动时重新链接文件,以避免链接断开。

  2. 另一个原因是避免浪费相同文件的多个副本所需要的存储空间,但又允许chrootsyscall受益于“主”文件系统根目录中的一部分文件(符号链接永远不能从外部引用文件)在chroot沙箱中,即使他们有相对路径)。

  3. ..子目录是存在硬链接的另一个非常重要但很少被提及的原因。这些..目录实际上是(在大多数unix fs实现中)到父目录的硬链接,没有硬链接则必须以完全不同的方式来实现,而硬链接的存在使得此实现非常容易。


1
对于第1点,使用uuids作为文件的“规范”名称,并使所有人类可读的名称成为uuids的符号链接是另一种解决方案。
R.,

尽管uuid的建议听起来在学术上是正确的,但将uuid用作文件名听起来并不实际,而且,目标是简化事物,而不是使它们变得更困难或“使人难以理解”。此外,具有用于“规范”文件引用的uudis只是对实际文件inode的附加间接寻址,因此,此方法没有意义,因为它没有优点,只是缺点,例如:对性能的影响,附加磁盘空间来存储更多目录条目,周围有一堆带有“怪异”名称的文件……
Marcelo

5

需要硬链接的非常常见的真实示例:

git clone --reference <repository>

这是从本地Git存储库中克隆的,复制几乎为零。与其复制目标文件(Git用于其“数据库”的不可变文件),不如将其硬链接。

任何存储库都可以删除对象,但是索引节点在其余存储库中仍然有效。而且,如果从所有存储库中删除了一个对象,则会从磁盘中删除该对象。硬链接可提供美观而强大的解决方案。在CI服务器中非常常见。


有一个非硬链接版本:git clone --shared <repository>。但是,由于每个人都在同一个目录上工作,因此这是易变的,还有很多警告。


4

最近,我有一个用例,用于基于U-Boot的系统的安全性较高的更新过程,其中uImage是一个指向要引导映像的软链接,其思想是断电不会造成任何问题,无论在何时中断。处理过程(假设文件系统运行):

ln image.bin backup_image.bin
ln -sf backup_image.bin uImage

// replace image.bin

ln -sf image.bin uImage
rm backup_image.bin

没有硬链接就不会那么简单。

/编辑:

由于有了这些评论,我现在知道这样做会更好:

ln image.bin backup_image.bin
ln -sf backup_image.bin uImageNew
mv uImageNew uImage || rm -rf uImage && mv uImageNew uImage

// replace image.bin

ln -sf image.bin uImageNew
mv uImageNew uImage || rm -rf uImage && mv uImageNew uImage
rm backup_image.bin

rm这里是为了能够更好地逃脱一个奇怪的状态,例如,如果uImage某件事出乎意料而会mv失败[但不一定是先前的ln -sf解决方案]。)


2
+1是因为从概念上讲这是一个很好的理由,但不幸的ln -sf是不是原子的。它将删除旧的符号链接并创建一个新的符号链接。要解决此问题,您需要创建一个带有临时名称的新符号链接,并将其rename(2)mv)替换为您要替换的符号链接的名称。
R.,

@R ..你是对的!😲 stat("uImage", {st_mode=S_IFREG|0777, st_size=0, ...}) unlink("uImage")symlink("backup_image.bin", "uImage")
PHK

1
顺便说一句,在这里看到我的版本中install.sh解决该问题:git.musl-libc.org/cgit/musl/tree/tools/install.sh
R.,

@R ..请注意,如果目标已经存在,例如符号链接是符号链接循环的一部分,则mv即使使用也会-f失败。演示:ln -sf foo bar; ln -sf bar foo; echo "Before:"; ls -l foo bar; >testfile; mv testfile foo || { echo "Using mv -f"; mv -f testfile foo; }; echo "After:"; ls -l foo bar
phk

3

我对硬链接的一种用途是下载或解压缩损坏的文件时。进行下载或解压缩的程序(例如unzip或unrar)在遇到错误时通常会自动删除不完整的文件,通常没有选择保留它。如果要保留该文件,可以对其进行硬链接。


3

BackupPC是一个备份系统,它使用服务器上的硬链接来提供文件级重复数据删除。

首先根据文件的md5哈希将文件存储在“池”目录树中。任何使用该文件的备份都会硬链接到池文件。随着备份过期/删除,其硬链接将从文件系统中删除。

此处,硬链接优于软链接,因为它们提供了自动引用计数。cron作业会定期删除池目录中没有多个链接的任何文件。

这种方法有一些缺点(主要是很难使用基于文件系统的工具来复制备份存储),但实践证明它非常健壮。


另一个用例:tomcat Java Web应用程序服务器将文件名视为元数据。必须根据Web服务器上的路径命名Java“ war”文件。

例如:foo.war 是提供网址的Java代码/foo

不幸的是,它在做出此决定之前会解决符号链接。

因此,假设您想部署一个应用程序构建,并为其提供一个描述性文件名(例如,带有发行号或日期)。您不能使用“真实”名称对文件进行符号链接-您必须进行硬链接。

foo.war链接到foo-20170129.war不起作用

foo.war硬链接到foo-20170129.war作品。

我不喜欢这种tomcat行为,但是硬链接为我提供了解决方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.