我正在读索贝尔的书Linux 命令、编辑器和 Shell 编程实用指南,4e。早些时候,他谈到了.
和 ,..
并说它们是工作目录和工作目录父目录的“路径名的同义词”。我的问题是我是否应该将它们视为相对路径名或绝对路径名的同义词。最后,我认为我的误解与不了解 Linux 系统如何解析路径名有关。
举个例子:假设我输入如下命令
cd ..
我是否应该将 shell 视为用 .. 替换当前工作目录的父目录的绝对路径名?或者,当我给出相对路径名时,“分辨率”的行为是否有所不同(这里似乎是这种情况,因为我没有以斜杠 / 开始我的路径)?在某种程度上,我想这个问题可以表述为“相对路径命名是绝对路径命名的特殊情况吗?因为每个相对路径名都替换为适当的绝对路径?”
答案1
.
并..
表示它们是工作目录和工作目录父目录的“路径名同义”
这是一个简化。在大多数情况下都是如此,但并非总是如此。大多数情况下,如果当前目录是/one/two/three
,则cd .
相当于cd /one/two/three/.
相当于cd /one/two/three
,并且cd ..
相当于cd /one/two/three/..
相当于cd /one/two
。类似地,ls .
相当于ls /one/two/three
且ls ..
相当于ls /one/two
。
等效性不取决于外壳。这是解决.
和 的内核工作的一部分..
。从历史上看,.
和..
实际上是普通的目录条目,内核没有任何代码来处理路径遍历中的这些条目。.
和的唯一特殊代码..
是它们在每个目录中自动创建,并且无法修改或删除。现代系统往往不将.
和存储..
为目录条目,而是在其路径遍历代码中进行特殊处理。
您可以观察到 shell 不会通过将路径传递给外部命令来解决问题.
。..
$ echo ..
..
$ ls ../s*
../somefile ../someotherfile
正如我上面所写,在大多数情况下,解析相对路径相当于指定绝对路径,但并非全部。例如,可以运行这样的应用程序:
创建目录和文件:
drwx------ 4 root root 4096 Jan 1 12:00 /some drwx------ 2 myapp root 4096 Jan 1 12:00 /some/where -rwx------ 1 myapp root 4096 Jan 1 12:00 /some/where/myfile
以 root 身份更改到目录
/some/where
。放弃用户的权限
myapp
。应用程序可以访问
myfile
and./myfile
,但不能访问/some/where/myfile
or../where/myfile
,因为它没有遍历 的权限/some
。
请注意,这是同一文件的路径之间等效性的一般限制,而不仅仅是.
和..
。
有一种特殊情况是..
在 shell 内部处理的:cd
仅对于命令(以及相关命令,例如pushd
),shell 本身会压缩/dir/..
为空。这包括将当前目录视为cd ..
根据shell 进行处理。这通常被认为对人类更友好。特别是,紧随其后可让您回到起点。当涉及符号链接时,这会产生影响。如果是不是到同一目录中的子目录的符号链接,则不是当前目录:它是该目录的父目录cd /one/two
/one/two/three
cd foo
cd ..
link
link/..
目标的link
。这称为“逻辑”当前目录跟踪,您可以使用或通过在某些 shell 中设置 shell 选项来切换到“物理”当前目录跟踪(其中 shell 不执行任何特殊处理..
) 。cd -P
答案2
我的问题是我是否应该将这些视为相对路径名或绝对路径名的同义词
我建议跳过这个阶段,像任何其他目录一样直接思考这些,因为这就是它们的目的是以与您相关的所有方式(除非您是内核或文件系统模块开发人员)。
吉尔斯的回答很好,我看不出其中有什么特别错误的信息。
也就是说:查看“.”绝对是可能且有用的。和“..”作为沼泽标准目录。无论您在脚本或应用程序中使用它们做什么,它们都像目录一样工作(正如吉尔斯所说,在过去的某些时候它们实际上是目录)。
最重要的是:你必须保持一个概念索引节点与 a 分开目录项在你的脑海里。索引节点描述了“某些内容”存储在文件系统中的位置(以相当物理的方式,即磁盘块)。这目录项是一个更抽象的表示,包含人类可读的名称、相应的索引节点、属性、日期等。
A目录它本身可以像内部处理的文件一样被罚款,该文件具有一些用于列出这些条目的表示(当然这是简化的)。重要的是实际情况贮存与有关信息的地方非常分开在哪里它已被存储。
如果我输入以下内容,我可以看到这些目录的索引节点(第一列):
~/tmp$ ls -ilaO
total 8
16326296 drwxr-xr-x 8 me staff - 256 Jan 15 14:02 .
1129613 drwxr-xr-x+ 112 me staff - 3584 Jan 19 17:25 ..
16326815 drwxr-xr-x 2 me staff - 64 Jul 27 2020 a_directory
126333718 -rw-r--r-- 1 me staff - 0 Jan 15 14:07 a_file
转到“楼上”,我可以检查tmp
其父目录中的表示方式:
~$ ls -ilaO -d tmp
16326296 drwxr-xr-x 8 me staff - 256 Jan 15 14:02 tmp
tmp
正如预期的那样,父目录中的 in 指向与.
inside相同的 inode tmp
。
检查.
父目录的:
~$ ls -ilaO -d .
1129613 drwxr-xr-x+ 112 me staff - 3584 Jan 19 17:25 .
显示父目录中的 inode与子目录中条目.
的 inode 相同,正如预期的那样。..
我可以在几乎所有可以使用系统中其他目录名称的地方使用.
and 。..
如果有什么区别,这是因为我使用的命令出于某种原因实现了特殊逻辑(例如出于安全原因 - Web 服务器可以强制路径永远不能包含,..
因此某人无法“逃避”安全规则)并输入类似 http://domain/index.html/../../../../etc/passwd 的 URL 以获取密码文件)。
其他程序(例如bash
)可能有某种特殊的魔术句柄“..”。例如,当我执行 a 时,cd ..
bash 知道我当前的路径/where/i/was/before/..
不是/where/i/was
.这回答了您关于如何思考 shell 的问题:您可以想象它只是做它认为您想要实现的事情,让您更轻松。其他没有特殊逻辑的程序..
通常可以轻松地..
在其路径中的任何地方工作,并且会愉快地不知道它们 - 一切都会正常工作,因为..
是与任何其他路径名一样的路径名。
答案3
.
和的解析..
发生在内核中。当您沿着路径下降时,内核会初始化 dnode 条目。当前目录 dnode 条目有一个指向其父目录 dnode 条目的指针。
可以看出,文件系统代码在这里没有发挥作用。如果您损坏了目录..
条目以引用其他地方,则实际查看此内容的唯一方法是通过手工制作的 NFSv2 客户端。这是非常正确的,如果你损坏了一个文件系统,一个目录有两个路径,它..
仍然可以正常工作,你将沿着你进入的路径下降。
某些 shell 会cd ..
通过将最后一个组件作为文本从路径中剥离来进行特殊处理,当当前目录路径是符号链接时,这会导致不同的行为。 shell 不知道哪些参数是文件名参数,并且..
不是 glob 模式;通过执行echo ..
和观察返回的结果可以很容易地看出这一点。
资料来源:我为我的硕士论文开发了一个文件系统。