为什么ls命令中的当前目录被标识为链接到自身?

在“学习UNIX操作系统”一书中,有一节:“3.1.8列出文件”,它描述了ls命令。

ls -l的段落中,它描述了该命令输出的列。

ls -l命令的第二列包含一个数字。 这个数字在书中描述为“与此链接的文件和目录的数量”。 (链接到与相关数字相同的行的最后一列中指定的文件或目录。)

我尝试了这个命令,并将输出与当前目录中的实际文件和目录数量进行了比较。

 ls -l drwxr-xr-x 6 azbc staff 192 Sep 7 16:09 test 

在目录test ,我有2个子目录和1个文件,1个隐藏文件和当前目录的列表,以及父目录的列表,因此共有6个文件和目录。

  ls -a -F ./ .hidden_file.txt dir_2/ ../ dir_1/ file_1.sh 

我认为将所有文件和目录(包括隐藏文件和目录)标识为链接到当前目录似乎是合乎逻辑的。 将父目录标识为链接到当前目录似乎也是合乎逻辑的。

但为什么当前目录被识别为与自身相关联?

测试目录的ls -la命令提供以下输出。 (对于目录名后面的目录,-F选项显示/ ,如果是可执行文件,则显示*)

  ls -la -F total 0 drwxr-xr-x 6 azbc staff 192 Sep 7 16:09 ./ drwxr-xr-x+ ?? azbc staff ?? Sep 7 16:06 ../ -rw-r--r-- 1 azbc staff 0 Sep 7 16:09 .hidden_file.txt drwxr-xr-x 2 azbc staff 64 Sep 7 16:06 dir_1/ drwxr-xr-x 2 azbc staff 64 Sep 7 16:06 dir_2/ -rwx--x--x 1 azbc staff 0 Sep 7 16:06 file_1.sh* 

文件本身仅用一个链接标识。 文件是否链接到自身? 或者它链接到它所在的目录?

由于在目录列表中,目录本身在列表中表示,因此逻辑上被计为链接。

但是,在文件列表本身中,只有文件本身在列表中表示。

  ls -la -F file_1.sh -rwx--x--x 1 azbc staff 0 Sep 7 16:06 file_1.sh 

这使得文件与自身链接是合乎逻辑的。

但是,对我说这个文件链接到它所在的目录似乎更合乎逻辑。

这似乎不是后果。

或者链接文件的列表仅仅是对命令列表输出中存在的文件和目录的计数,而不是文件系统中文件或目录的真实链接的标识?

编辑:回复@George Udosen ,在:

“现在尝试在评论中回答您的问题:

‘这里被列为什么链接? 文件本身是否列出? 或者是包含列出文件的目录?’“

如果我列出目录test

  ls -la -F test ... drwxr-xr-x 2 azbc staff 64 Sep 7 16:06 dir_1/ ... -rwx--x--x 1 azbc staff 0 Sep 7 16:06 file_1.sh* 

它用2链接标识目录dir_1

如果我然后列出该目录test/dir_1

  ls -la -F test/dir_1 total 0 drwxr-xr-x 2 azbc staff 64 Sep 7 16:06 ./ drwxr-xr-x 9 azbc staff 288 Sep 7 21:37 ../ 

嘿,确实!! 它列出了2个条目!

文件file_1.sh*标识为1链接。 如果我列出文件file_1.sh

  ls -la -F test/file_1.sh -rwx--x--x 1 azbc staff 0 Sep 7 16:06 test/file_1.sh* 

何!! 它确实列出了1入口!! ,即file_1.sh本身! 并再次标识具有1条目的文件。

从这个方面我可以得出结论,列出的每个条目有1链接是一个文件,而不是一个目录? Ho,这似乎不是这种情况,因为符号链接也被列为具有1链接/ 1条目。

我建议您阅读什么是目录,如果Linux上的所有内容都是文件? 有关目录结构,历史和目录如何工作及其元素(inode, dirent结构等)的更深入的知识,尽管这个问题不是必需的。

什么是点’。’ 和点点’..’目录?

从1971版UNIX程序员手册看format of directories 手册页的 format of directories ,我们看到了...已经在那里:

按照惯例,每个目录中的前两个条目用于“。”。 和“……”。 第一个是目录本身的条目。

至于它们的意义,可以在Panos的答案中找到答案 。 Ken Thompson在1989年的采访中解释了..

每次我们创建一个目录时,按照惯例,我们将它放在另一个名为directory – directory的目录中,该目录是dd。 它的名字是dd,并且所有用户目录和实际上大多数其他目录,用户维护自己的目录系统,指针返回dd,dd缩短为 dot-dot, 和dd用于目录目录。 这是回到你可以到达系统中所有其他目录的地方,以维护这个意大利面碗

当然, . 因为你可以猜到代表directory d或短。 这样的目录本身自然地与目录的实际名称共享相同的inode号。 现在,这还没有解释为什么目录. 与自己有关,但我有几点想法。

0. Unix哲学

在Uresh Vahalia的1996年出版的“UNIX Internals:The New Frontiers”一书中,在第8章第222页中说明:

Unix支持每个进程的当前工作目录的thenotion,作为进程状态的一部分进行维护。 这允许用户通过其相对路径名引用文件,这些路径名是相对于当前目录解释的。

考虑到目录只是一个特殊文件,我们需要一致的相对文件名来引用目录本身,这将是一个特殊的文件名. ,它是从d进化而来的,它是目录的缩写。

1.技术优势

我能想到的主要优点是系统简化了inode查找,从而简化了元数据信息。 由于目录已经包含一个条目. 使用相同的inode,无需通过完整路径进行查询。 编程同样如此。 考虑一个非常简单的ls实现 。 在那里我使用getcwd()函数来获取当前工作目录路径,然后将其传递给opendir() 。 或者我可以扔掉getcwd()并直接使用opendir('.') 。 在旧的PDP-11终端中,内存大小只有几千字节,节省系统调用开销至关重要。

2.用户便利

请考虑以下示例:

 mv ../filename.txt . 

在Hendrik Jan Thomassen的演示中,有人提到由于旧的终端键难以按下,原始的Unix命令很短,因此实际上整天打字命令是一种物理上的努力。 如果您深入到目录树中,重新键入当前工作目录的完整路径将是乏味的。 当然, mv可以通过假设当我们执行mv 目标视为“当前工作目录”来实现。 我只能猜测为什么mv 占了上风,可能是由于当时其他编程语言的影响。

3.改进MULTICS

注意:我自己从未参与过MULTICS,所以这只是基于阅读在线资料

根据1986年MULTICS手册名称 :

相对路径名可以以一个或多个小于字符(“<”)开头。

>字符在MULTICS上用作路径分隔符(如Linux上的/ )。 可以说这可能看起来令人困惑。 因此,当引用命令时,。 ./可以说更清晰 – 我们引用位于当前工作目录中的文件名。

这可能对其他命令有益。 众所周知如何在Unix / Linux上创建文件: touch ./file 。 在MULTICS上,根据swenson.org ,可以通过或者add_name命令完成:

 cd foo r 18:03 0.041 1 an foo bar r 18:03 0.077 3 ls foo Directories = 1. sma foo bar r 18:03 0.065 0 

在旁注中,当涉及到时,有明显的相似性:导航一个目录是通过cwd <<完成的。

4.引用可执行文件

如果您每天都在运行脚本,那么您就知道./script.sh语法了。 它的原因很简单:shell的工作方式是它在PATH变量中查找可执行文件,因此当你提供./它不必在任何地方查找。 PATH变量的神奇之处在于使用echo而不是/bin/echo或其他非常冗长的路径。 现在假设您的路径中没有该script.sh ,并且它位于您当前的工作目录中。 你现在做什么 ? /very/long/path/to/the/executable/this/typing/gets/exhausting/on/PDP-11/finally/script.sh ? 这将抛弃Unix简单的所有概念! 因此,回到Unix哲学,它也符合优雅设计/简洁的原则。

当然,有些人想补充一下. 对于PATH ,但这实际上是一种非常糟糕的做法 ,所以不要这样做。

旁注...的特殊情况. 指向同一个是inode 2 - / dir,它是有意义的,因为它是目录树中的最高点。 当然, ..为NULL也可以工作,但它更优雅,使它指向/本身。


关于链接计数和目录硬链接的注意事项

正如Gilles正确指出的那样(并且由George Udosen引用),目录的链接计数以2( ..表示父目录和. )开头,所有其他链接都是子目录:

 # new directory has link count of 2 $ stat --format=%h . 2 # Adding subdirectories increases link count $ mkdir subdir1 $ stat --format=%h . 3 $ mkdir subdir2 $ stat --format=%h . 4 # Adding files doesn't make difference $ cp /etc/passwd passwd.copy $ stat --format=%h . 4 # Count of links for root $ stat --format=%h / 25 # Count of subdirectories, minus . $ find / -maxdepth 1 -type d | wc -l 24 

直观地说,只有子目录的目录链接才有意义,因为硬链接与原始文件同时存在。 除此之外,这些并不是硬链接 - 硬链接创建指向相同数据的文件名。 根据该定义,到目录的硬链接将包含相同的数据,即包含相同的文件列表。 如果删除了目录的所有硬链接,这将导致文件系统或许多孤立文件中的循环。 出于这个原因, 目录不允许创建硬链接 ,并且从另一个问题(我建议你阅读)中使用Gilles的措辞 “...... [事实上,许多文件系统确实在目录上有硬链接,但仅限于一种非常有纪律的方式......“那些是特殊情况...目录。

现在,问题变成目录上下文中“链接”的实际意义了吗? TL; DR:目录结构是树,这里的链接表示每个树项的子节点数(每个叶子,或没有子目录的目录,只有2个链接)。 特别是, ext3和ext4使用HTree,而xfs使用B +树


结论

最后,之所以如此. 与自身联系仅仅是因为它是好的设计。 Unix的原作者可能一直在他们时代的技术限制下工作,但他们是当时最聪明的人,或者他们经常被称为“巫师”,他们做事是有原因的。

你的问题对我来说很模糊,但我试着解释一下它是如何运作的,所以它可以帮助你理解它。

存储在系统中的每个文件都有一个数字(inode编号),让我们检查一下:

 $ ls -i -1 -a test/ 9186865 . 9175041 .. 

我使用-1来显示单列中的文件列表,使用-i显示inode,使用-a显示隐藏文件。

每个inode保存有关文件的信息,例如权限,所有者,大小,链接数,修改时间,指向实际文件数据的指针(但不包括文件名)。

每个目录都不过是一个特殊文件,包含一个名称(文件)列表和这些名称的相应inode。

因此,当我删除文件(也称为取消链接文件)时,我将从其父目录中删除其链接,但数据仍然存在于磁盘上。

默认情况下创建新目录时,它包含2个硬链接,表示默认情况下每个目录都有...在其列表中。

而你可能知道. 是当前目录的硬链接, ..是父目录的硬链接,所以如果我创建一个新目录:

 $ mkdir test $ ls -i -d test 9186865 drwxrwxr-x 2 ravexina ravexina 4096 Sep 7 19:37 test 

正如您所看到的链接数量是两个,现在我在此目录中创建的文件数量无关紧要,除非我开始创建目录,否则链接数量保持不变。 对于每个目录,该数字将递增1,现在您知道原因了! 因为每个新目录都包含一个到其父目录的硬链接: ..

还记得我对目录的看法吗?

每个目录都不过是一个特殊文件,包含一个名称(文件)列表和这些名称的相应inode。

链接实际上是这些名称,默认情况下,每个文件都有1个链接(创建时的名称),如果你创建一个到该文件的新硬链接(意味着另一个名称,在另一个目录或相同的目录中指向相同的数据[ inode])数字将增加1。

取自Gilles的优秀答案

从历史上看 ,第一个Unix文件系统在每个目录中创建了两个条目: . 指向目录本身,并指向其父目录。 这提供了一种简单的方法来遍历文件系统,包括应用程序和操作系统本身。

因此,每个目录的链接数为2 + n,其中n是子目录的数量。 链接是该目录在其父目录中的条目,该目录是自己的目录. 条目和每个子目录中的..条目。 例如,假设这是以/parent根的子树的内容,所有目录:

 /parent /parent/dir /parent/dir/sub1 /parent/dir/sub2 /parent/dir/sub3 

然后dir的链接数为5: /parentdir条目,即. /parent/dir条目,以及/parent/dir/sub1/parent/dir/sub2/parent/dir/sub3 。 由于/parent/dir/sub1没有子目录,因此其链接数为2( /parent/dirsub1条目和/parent/dir/sub1.条目)。

为了最小化根目录的特殊shell数量,根目录没有“正确”的父目录,根目录包含指向自身的..条目。 这样它的链接数也加上2加上子目录的数量,2是/./..

后来的文件系统倾向于跟踪内存中的父目录,通常不需要...作为实际条目存在; 典型的现代unix系统治疗...作为特殊值作为独立于文件系统类型的文件系统代码的一部分。 一些文件系统仍包括...条目,或假装即使磁盘上没有任何内容。

无论是否,大多数文件系统仍会报告目录的链接数为2 + n ...条目存在,但也有例外,例如btrfs不这样做。

现在尝试在评论中回答您的问题:

什么在这里被列为链接? 文件本身是否列出? 或者是包含列出文件的目录?

该链接属于文件而非目录,让我用一个例子来说明这个事实。 现在,如果我要做nano file.txt ,此处的链接将用于查找该文件的inode编号, inode将随后提供将使nano程序修改该文件的信息。 请记住, inode保存有关该文件的信息(无论是文件夹,文件还是块设备) 。

现在每个文件名必须链接到一个inode number ,以便在该文件上执行正常操作,因此是链接属于该文件而不是父文件。 我希望我能正确理解你的问题并回答它。