假设我登录到 unix 系统上的 shell 并开始敲击命令。我最初从用户的主目录开始~
。我可能会从那里cd
下到目录Documents
。
这里更改工作目录的命令非常简单直观地理解:父节点有一个它可以访问的子节点列表,并且大概它使用搜索的(优化的)变体来定位子节点的存在用户输入的名称,然后“更改”工作目录以匹配此 - 如果我在那里错了,请纠正我。甚至更简单的是,shell 只是“天真地”尝试完全按照用户的意愿访问目录,并且当文件系统返回某种类型的错误时,shell 会相应地显示响应。
然而,我感兴趣的是,当我向上导航目录时,相同的过程是如何工作的,即到父级或父级的父级。
鉴于我未知的,可能是“盲”的位置Documents
,可能是整个文件系统树中具有该名称的多个目录之一,Unix 如何确定我接下来应该放在哪里?它是否参考pwd
并检查了它?如果是,如何pwd
跟踪当前的导航状态?
其他答案过于简单化,每个都只呈现故事的一部分,并且在几点上是错误的。
有两种方法可以跟踪工作目录:
chdir()
andfchdir()
系统调用设置,后者由chroot()
./proc
可以在 Linux 操作系统上或通过fstat
FreeBSD 等上的命令间接看到它们:当路径名解析运行时,它从那些引用的 vnode 中的一个或另一个开始,这取决于路径是相对的还是绝对的。(作为第三个选项,有一系列
…at()
系统调用允许从打开(目录)文件描述符引用的 vnode 开始解析路径名。)在微内核 Unices 中,数据结构位于应用程序空间中,但保持对这些目录的开放引用的原则保持不变。
chdir()
。如果更改为相对路径名,它会操纵字符串以附加该名称。如果更改为绝对路径名,它会将字符串替换为新名称。在这两种情况下,它都会调整字符串以删除
.
和..
组件,并追踪符号链接,用它们的链接名称替换它们。(例如,这是 Z shell 的代码。)内部字符串变量中的名称由名为(或在 C shell 中)的shell 变量跟踪。这通常作为环境变量(名为)导出到由 shell 生成的程序。
PWD
cwd
PWD
这两种跟踪事物的方法由和 shell 内置命令的
-P
and-L
选项揭示,cd
以及pwd
shell 的内置pwd
命令与/bin/pwd
命令和内置命令之间的差异,pwd
例如(以及其他) VIM 和 NeoVIM。如您所见:获取“逻辑”工作目录是查看
PWD
shell变量(如果不是shell程序,则为环境变量)的问题;而获取“物理”工作目录是调用getcwd()
库函数的问题。/bin/pwd
使用该选项时程序的操作-L
有些微妙。它不能信任PWD
它继承的环境变量的值。毕竟,它不需要被 shell 调用,干预程序可能没有实现 shell 的机制,即使PWD
环境变量始终跟踪工作目录的名称。或者有人可能会做我刚刚在那里做的事情。所以它所做的是(正如 POSIX 标准所说)检查中给出的名称是否与 name
PWD
产生相同的东西.
,如系统调用跟踪所示:如您所见:它仅
getcwd()
在检测到不匹配时调用;并且可以通过设置PWD
一个确实命名相同目录但路径不同的字符串来欺骗它。库
getcwd()
函数本身就是一个主题。但具体来说:..
。当它到达..
与其工作目录相同的循环或尝试打开下一个错误时,它会停止..
。这将是大量的系统调用。但是,请注意,即使在 FreeBSD 和其他操作系统上,内核也不会使用字符串跟踪工作目录。
导航到
..
本身又是一个主题。另一个概要:虽然目录通常(尽管已经提到,这不是必需的)在磁盘上的目录数据结构中包含实际..
的目录数据结构,但内核跟踪每个目录 vnode 本身的父目录,因此可以导航到..
任何 vnode工作目录。挂载点和更改的根机制有些复杂,这超出了此答案的范围。在旁边
Windows NT 实际上做了类似的事情。每个进程有一个工作目录,由
SetCurrentDirectory()
API 调用设置,并由内核通过该目录的(内部)打开文件句柄跟踪每个进程;并且有一组环境变量,Win32 程序(不仅是命令解释器,而是所有Win32 程序)使用来跟踪多个工作目录的名称(每个驱动器一个),在它们更改目录时附加或覆盖它们。通常,与 Unix 和 Linux 操作系统不同,Win32 程序不会向用户显示这些环境变量。但是,有时可以在 Windows NT 上运行的类 Unix 子系统中看到它们,也可以通过以
SET
特定方式使用命令解释器的命令来看到它们。进一步阅读
pwd
”。 开放组基本规范第 7 期。IEEE 1003.1:2008。公开组。2016 年。内核不跟踪目录或文件名;文件或目录在内核中由 inode/device 对表示。
chdir()
像,等系统调用open()
将路径作为参数,它可以是绝对路径(例如/etc/passwd
),也可以是相对于当前目录的路径(例如:Documents
,..
)。当进程执行chdir("Documents")
时,会在当前工作目录中进行查找Documents
,并更新进程的工作目录以引用该目录。从内核的角度来看,名称“..”没有什么特别之处,它只是文件系统中..
引用父目录的约定。该
getcwd()
函数不是系统调用,而是一个库函数,它必须一直运行到根目录,并在途中记录路径组件的名称。有趣的是,传统
cd ..
上比pwd
. 命名..
的目录被明确地放置在文件系统中。系统跟踪当前目录的设备/inode,所以cd ..
或更准确地说,系统调用chdir("..")
只需要在属于当前目录的inode的文件中查找名称“..”并将当前目录的设备/inode更改为在那里找到的价值。pwd
(更准确地说/bin/pwd
)..
依次跟随链接并读取相应的目录,直到找到它来自的 inode,反向组装这些名称的列表,直到它到达根目录(特别是不包含..
条目)。现在这是原始的低级基本行为。相反,实际的 shell 命令
pwd
依赖于各种缓存当前路径名的技术。但在核心,只有它的 inode 才是真正已知的。这意味着一旦使用符号链接来导航目录,当前 shell 和系统的当前工作目录名称概念/bin/pwd
可能会有所不同。