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

azb*_*zbc 6 command-line

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

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

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

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

ls -l
drwxr-xr-x   6 azbc  staff    192 Sep  7 16:09 test
Run Code Online (Sandbox Code Playgroud)

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

 ls -a -F
 ./                .hidden_file.txt  dir_2/
 ../               dir_1/            file_1.sh
Run Code Online (Sandbox Code Playgroud)

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

但是为什么当前目录被标识为链接到自身?

ls -latest 目录的命令提供以下输出。( -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*
Run Code Online (Sandbox Code Playgroud)

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

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

但是,在文件本身的列表中,列表中仅表示文件本身。

 ls -la -F file_1.sh
 -rwx--x--x  1 azbc  staff  0 Sep  7 16:06 file_1.sh
Run Code Online (Sandbox Code Playgroud)

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

但是,我认为文件链接到它所在的目录似乎更合乎逻辑。

这似乎不是结果。

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

编辑:作为对@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*
Run Code Online (Sandbox Code Playgroud)

dir_12链接标识目录!

如果我然后列出该目录 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 ../
Run Code Online (Sandbox Code Playgroud)

嘿,确实!!它列出了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*
Run Code Online (Sandbox Code Playgroud)

呵!!它确实列出了1条目!,也就是file_1.sh它自己!并再次用1条目标识该文件。

顺便说一下,我可以得出结论,列出的每个具有1链接的条目都是文件而不是目录吗?何,情况似乎并非如此,因为符号链接也被列为具有1链接/1条目。

Ser*_*nyy 4

我建议您阅读什么是目录,如果 Linux 上的一切都是文件?有关目录结构、历史以及目录如何工作及其元素(索引节点、dirent结构等)的术语的更深入的知识,尽管这不是本问题所必需的。

\n\n

什么是点\'.\'和点-点\'..\'目录?

\n\n

查看UNIX 程序员手册format of directories 1971 年版的手册页.,我们看到并且..已经存在:

\n\n
\n

按照惯例,每个目录中的前两个条目\n 代表“.”。和 \xe2\x80\x9c..\xe2\x80\x9c。第一个是目录本身的条目。

\n
\n\n

至于它们的意义,可以在Panos的回答中找到答案。Ken Thompson在1989 年的采访中解释了这是怎么..发生的:

\n\n
\n

每次我们创建一个目录时,按照惯例我们都会将它放在另一个目录中,称为directory-directory,即dd。它的名称是 dd,所有用户目录以及实际上大多数其他目录,用户维护自己的目录系统,有指向 dd 的指针,并且 dd 被缩短为 \xef\xbf\xbddot-dot,\xef\xbf\xbd dd 表示目录-目录。这是您可以访问系统中所有其他目录来维护这个意大利面条碗的地方

\n
\n\n

当然,.正如您可以猜到的,代表d或缺少directory。这样的目录本身自然与目录的实际名称共享相同的索引节点号。现在,这仍然不能解释为什么目录.会链接到自身,但我有几个想法。

\n\n

0.Unix哲学

\n\n

在 Uresh Vahalia 于 1996 年出版的《UNIX 内部结构:新前沿》一书中,第 8 章第 222 页中指出:

\n\n
\n

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

\n
\n\n

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

\n\n

1、技术优势

\n\n

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

\n\n

2. 用户便利性

\n\n

考虑以下示例:

\n\n
mv ../filename.txt .\n
Run Code Online (Sandbox Code Playgroud)\n\n

Hendrik Jan Thomassen 的演讲中提到,由于旧的终端键很难按下,原始的 Unix 命令很短,因此整天键入命令是一项体力劳动。如果您深入目录树,重新输入当前工作目录的完整路径将是乏味的。当然,mv可以通过假设当我们这样做时mv <file>我们暗示目的地为“当前工作目录”来实现。我只能猜测为什么mv <original> <new>会流行,也许是由于当时其他编程语言的影响。

\n\n

3. 相对 MULTICS 的改进

\n\n

注意:我自己从未参与过 MULTICS 工作,因此这仅基于阅读在线资源

\n\n

根据 1986 年有关路径名的 MULTICS 手册

\n\n
\n

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

\n
\n\n

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

\n\n

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

\n\n
cd foo\nr 18:03 0.041 1\n\nan foo bar\nr 18:03 0.077 3\n\nls foo\n\nDirectories = 1.\n\nsma  foo\n       bar\n\nr 18:03 0.065 0\n
Run Code Online (Sandbox Code Playgroud)\n\n

顺便说一句,在以下方面有明显的相似之处..:向上导航一个目录是通过cwd <<.

\n\n

4. 引用可执行文件

\n\n

如果您每天运行脚本,那么您就很了解./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 哲学,它也符合优雅设计/简单的原则。

\n\n

当然,有些人想添加.PATH,但这实际上是一个非常糟糕的做法,所以不要这样做。

\n\n

旁注..:和.指向相同的 特殊情况是 inode 2 - / dir ,它是有意义的,因为它是目录树中的最高点。当然,..设为 NULL 也可以,但让它指向/自身会更优雅。

\n\n
\n\n

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

\n\n

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

\n\n
# new directory has link count of 2\n$ stat --format=%h .\n2\n# Adding subdirectories increases link count\n$ mkdir subdir1\n$ stat --format=%h .\n3\n$ mkdir subdir2\n$ stat --format=%h .\n4\n# Adding files doesn\'t make difference\n$ cp /etc/passwd passwd.copy\n$ stat --format=%h .\n4\n# Count of links for root\n$ stat --format=%h /\n25\n# Count of subdirectories, minus .\n$ find / -maxdepth 1 -type d | wc -l\n24\n
Run Code Online (Sandbox Code Playgroud)\n\n

直观上,目录的链接只是子目录 - 是有道理的,因为硬链接与原始文件具有相同的时间。不过,这些并不完全是硬链接 - 硬链接创建一个指向相同数据的文件名。根据该定义,目录的硬链接将包含相同的数据,即包含相同的文件列表。如果删除目录的所有硬链接,这将导致文件系统中出现循环或大量孤立文件。因此,目录不允许创建硬链接,并使用Gilles在另一个问题中的措辞(我建议您阅读)“...[i]事实上,许多文件系统确实在目录上有硬链接,但只能以非常有纪律的方式......”这些是...目录的特殊情况。

\n\n

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

\n\n
\n\n

结论

\n\n

归根结底,之所以.与它本身挂钩,只是因为它的设计很好。Unix 的原始作者可能一直在他们那个时代的技术限制下工作,但他们是当时最聪明的人,或者经常被称为“奇才”,他们做事是有原因的。

\n