确定文件是硬链接还是符号链接?


51

我正在创建一个shell脚本,该脚本将使用文件名/文件路径并确定文件是符号链接还是硬链接。

唯一的是,我不知道如何查看它们是否是硬链接。我创建了2个文件,一个是硬链接,另一个是符号链接,用作测试文件。但是,如何确定文件是Shell脚本中的硬链接还是符号文件?

另外,如何找到符号链接的目标分区?因此,假设我有一个链接到其他分区的文件,我如何找到该原始文件的路径?


16
硬链接是什么意思?所有文件都是硬链接。
terdon

1
@terdon ln /foo/bar/ /foo/bar2进行硬ln -s /foo/bar /foo/bar2链接,同时进行符号链接,这就是他的意思吗?
DisplayName 2014年

14
@DisplayName是的,但是所有文件都是指向其inode的硬链接。这就是Linux文件系统的工作方式。在您的示例中,bar2bar都是硬链接,只是指向同一个inode。
terdon

10
@DisplayName是的,它们是与其他inode的硬链接。这里没有矛盾。文件是指向索引节点的链接。那就是文件的定义。就您而言,这些链接位于不同的位置,但这不会更改基础数据结构。我的观点是,两者barbar2同等重要。一个不是到另一个的链接,它们都是链接,但指向同一个inode。
terdon

3
@Scott,不,我是说常规文件是硬链接,并且创建的硬链接与ln常规文件没有什么不同。
terdon

Answers:


42

吉姆的答案说明了如何测试符号链接:使用test-L测试。

但是严格来讲,测试“硬链接”并不是您想要的。硬链接之所以起作用,是因为Unix处理文件的方式:每个文件都由一个inode表示。然后,单个索引节点具有零个或多个名称目录条目,或者从技术上讲,具有硬链接(即您所说的“文件”)。

值得庆幸的是,该stat命令(如果有的话)可以告诉您一个inode有多少个名称。

因此,您正在寻找类似这样的东西(此处假设使用的GNU或busybox实现stat):

if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
    echo "File has more than one name."
fi

-c '%h'stat指示仅输出到索引节点的硬链接数,即文件具有的名称数。-gt 1然后检查是否大于1。

请注意,符号链接与其他文件一样,也可以链接到多个目录,因此您可以将多个硬链接链接到一个符号链接。


好的,为了清楚起见,我可以使用stat命令输出该文件具有的硬链接数,如果其大于1,则它在分区上的某个位置链接了另一个文件。
k-Rocker 2014年

@ k-Rocker是的。然后,它在分区上的某处具有第二个名称。
derobert 2014年

1
在OS X或* BSD上为stat -f %l /path/to/filegstat -c %h /path/to/file如果您安装的GNU coreutils没有默认名称(在OS X上为Homebrew),则也可以使用。
GDP2 2016年

29

一个例子:

$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3

f1f2f3目录条目是相同的文件(相同的inode:10802124,你会发现数量链接为3)。它们是指向相同常规文件的硬链接。

s4并且s5也是相同的文件(10802384)。它们的类型为symlink,而不是常规的。他们在这里指向一条道路s3。因为s4s5是同一目录的条目,所以两者的相对路径均s3指向同一文件(索引为10802347的文件)。

如果执行ls -Ll,则要求在解决符号链接后获取文件信息:

$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5

您会发现它们都解析为同一文件(10802124)。

您可以检查文件是否是的符号链接[ -L file ]。同样,您可以使用来测试文件是否为常规文件[ -f file ],但在这种情况下,检查是在解析符号链接之后进行的。

硬链接不是文件的类型,它们只是文件(任何类型)的不同名称。


19

使用命令的-h-L运算符test

-h file 
true if file is a symbolic link

-L file 
true if file is a symbolic link

http://www.mkssoftware.com/docs/man1/test.1.asp

根据此SO线程,它们具有相同的行为,但是-L是首选的。


好的,但是硬链接呢?我检查了脚步,但硬链接一无所获。如果-L返回false,是否表示它是硬链接?还是普通文件?
k-Rocker 2014年

1
硬链接共享相同的内容inode。另外,软链接l在其ls -l输出的开头会显示一个...我想您可以将这些规则放到脚本中,再加上[[ -L file ]]测试以查看给定文件是soft还是hard
jimm-cl 2014年

好的,我如何找到符号链接的目标分区?
k-Rocker 2014年

3

这里有很多非常正确的答案,但是我认为没有人真正解决过最初的误解。最初的问题基本上是“当我建立符号链接时,以后很容易识别它。但是我不知道如何识别硬链接。” 是的,答案基本上可以归结为“您不能”,或多或少地解释了原因,但似乎没有人承认这确实是令人困惑和奇怪的事情。

如果您正在阅读所有这些内容,并且已经弄清楚正在发生的事情,那么您就很好。您无需阅读我的内容。如果您仍然感到困惑,请继续。

真正简短的答案是,硬链接根本不是链接,完全不是符号链接。这是目录结构中的一个新条目,它指向原始目录条目所做的相同的一堆字节,一旦创建它,​​它与第一个条目一样“真实”且合法。驱动器上的每个 “普通”文件都至少具有一个硬链接。不,你不会看到它在任何目录,将无法引用或使用它。因此,如果您有一个文件Fred.txt,并且将Wilma.txt和Barney.txt硬链接到该文件,则这三个名称(和目录条目)都引用同一个文件,并且它们都同样有效。当您在文本编辑器中单击“保存”时,操作系统没有任何办法告诉其中一个条目是创建的,而其他条目是使用“ ln”命令创建的。

但是,操作系统确实必须跟踪指向同一文件的条目数。如果删除Wilma.txt,则不会释放驱动器上的任何空间也就不足为奇了。但是,如果删除Fred.txt(“原始”文件),则仍然不会释放驱动器上的任何空间,因为驱动器上的数据也被称为Fred.txt,但它仍然也是Barney.txt。仅当删除所有目录条目时,操作系统才会取消分配数据本身正在占用的空间。

如果Barney.txt是符号链接,则删除Fred.txt 取消分配空间,而Barney.txt现在将是断开的链接。另外,如果您移动或重命名带有指向该文件的符号链接的文件,则会断开该链接。但是您可以随意移动或重命名硬链接的文件,而不会破坏指向该文件/数据的其他目录条目,因为所有这些目录条目都是引用驱动器上同一数据块的目录条目(通过使用该数据的inode号)。

[这是两年后,这最后一点困惑了我一分钟,所以我想我会澄清。如果键入“ mv ./Wilma.txt ../elsewhere/Betty.txt”,则似乎是在移动文件,但实际上并非如此。您真正要做的是从当前目录的目录列表中删除一个行项目,该行中显示“名称'Wilma.txt'与可以使用inode ######找到的数据相关联#”,然后在目录../elsewhere的目录列表中添加一个新行项目,其中显示“名称'Betty.txt'与可以通过inode #######找到的数据相关联”。这就是为什么只要将文件移动到同一驱动器上的另一个位置,就可以像移动2 KB文件一样快地“移动” 2 GB文件。

因为操作系统必须跟踪指向同一数据块的目录中有多少个不同的目录,所以即使您无法确定目录条目是否指向您,也可以确定是否已将特定文件硬链接到该文件。 '正在看的是'原始'的还是没有的。一种方法是“ ls”命令,特别是“ ls -l”(即破折号后的小写字母L)

借用先前的示例。

 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1

第一个字母是破折号,所以它不是目录或其他奇特的东西,而是一个“常规”普通文件。但是,如果它确实是普通的,则rwx-ish部分后面的数字将为“ 1”,例如,“有一个目录条目指向此数据块。” 但这是硬链接演示的一部分,因此改为显示“ 3”。

请注意,这可能会导致奇怪和神秘的行为(也就是说,如果您没有将头缠在硬链接上)。如果您在文本编辑器中打开Fred.txt并进行一些更改,您会在Wilma.txt和Barney.txt中看到相同的更改吗?也许。大概。如果您的文本编辑器通过打开原始文件并写入更改来保存更改,则可以,所有三个名称仍将指向相同(新更改)的文本。但是,如果您的文本编辑器创建了一个新文件(Fred-new-temp.txt),将更改后的版本写入该文件,然后删除Fred.txt,然后将Fred-new-temp.txt重命名为Fred.txt,Wilma和Barney将仍然指向原始版本,而不是新的更改版本。如果您不了解硬链接,则可能会使您有点生气。:) [好吧,实际上我个人并不知道可以执行新文件/重命名功能的文本编辑器,但是我确实知道许多其他程序可以做到这一点,因此请保持警惕。]

最后一点:“ fsck”(文件系统检查)检查的一件事是驱动器上是否存在某些目录条目不再引用的数据块。有时会出问题,指向索引节点的唯一目录条目会被删除,但驱动器空间本身不会被标记为“可用”。因此,fsck的工作之一是将所有分配的空间与所有目录条目进行匹配,以确保没有任何未引用的文件。如果找到某些目录,它将创建新的目录条目,并将其放入“丢失+找到”目录。


只是想知道,那些“其他完全可以做到这一点的程序”是什么?
phk

@phk不知道他在想什么,但这是一种很常见的方法,可能会花费很长时间,并且如果失败会导致您处于不确定的状态。例如,如果您尝试从远程服务器下载,并且知道服务器可能会超时,则一种方法是将全部内容下载到临时文件。这样,如果下载出现问题,您仍然拥有原始文件。
cwallenpoole 2016年

我唯一知道的程序是FreeHand,因为如果/在保存期间崩溃时,将保留一个临时文件,而不是原始文件。但是我也看到其他程序也这样做。目前,我无法提供具体示例。
Snarke '17

2

您可以使用readlink FILE; echo $?。如果是硬链接,则返回1;如果是符号链接,则返回0。

在手册页中:“当作为readlink调用时,仅打印符号链接的目标。如果给定的参数不是符号链接,则readlink将不打印任何内容并退出并出现错误。”

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.