其他答案是过于简单化,每个答案仅代表故事的一部分,在两点上都是错误的。
跟踪工作目录有两种方式:
- 对于每个进程,在代表该进程的内核空间数据结构中,内核将两个vnode引用存储到该进程的工作目录和根目录的vnode。前一个参考由
chdir()
和fchdir()
系统调用设置,后者由设置chroot()
。可以/proc
在Linux操作系统上或通过fstat
FreeBSD等上的命令间接看到它们:%fstat -p $$ |头-n 5
用户CMD PID FD安装INUM模式SZ | DV读/写
JdeBP zsh 92648文本/ 24958 -r-xr-xr-x 702360 r
JdeBP zsh 92648 ctty / dev 148 crw--w ---- pts / 4 rw
JdeBP zsh 92648 wd / usr / home / JdeBP 4 drwxr-xr-x 124 r
JdeBP zsh 92648根/ 4 drwxr-xr-x 35 r
%
路径名解析操作时,根据路径是相对还是绝对,它从这些引用的vnode中的一个或另一个开始。(有一系列…at()
系统调用,它们允许路径名解析从打开的(目录)文件描述符所引用的vnode开始,作为第三个选项。)
在微内核Unices中,数据结构位于应用程序空间中,但是保留对这些目录的开放引用的原理仍然相同。
- 在内部,在诸如Z,Korn,Bourne Again,C和Almquist外壳之类的外壳中,该外壳还使用内部字符串变量的字符串操作来跟踪工作目录。只要有原因调用,它就会执行此操作
chdir()
。如果更改为相对路径名,它将操纵字符串以追加该名称。如果更改为绝对路径名,它将用新名称替换字符串。在这两种情况下,它都会调整字符串以删除.
和..
组成部分,并追逐符号链接,并用其链接名称替换它们。(例如,这是Z shell的代码)。
内部字符串变量中的名称由名为(或在C shell中)的shell变量跟踪。通常,它作为环境变量(名为)导出到shell生成的程序中。PWD
cwd
PWD
这两种跟踪事物的方法由-P
and 和shell内置命令的and -L
选项cd
以及pwd
shell的内置命令与诸如此类(以及其他)之类pwd
的/bin/pwd
命令和内置命令之间的差异揭示。pwd
VIM和NeoVIM。
%mkdir a; ln -sab
%(cd b; pwd; / bin / pwd; printenv PWD)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / a
/ usr / home / JdeBP / b
%(cd b; pwd -P; / bin / pwd -P)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
%(cd b; pwd -L; / bin / pwd -L)
/ usr / home / JdeBP / b
/ usr / home / JdeBP / b
%(cd -P b; pwd; / bin / pwd; printenv PWD)
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
/ usr / home / JdeBP / a
%(cd b; PWD = / hello /那里/ bin / pwd -L)
/ usr / home / JdeBP / a
%
如您所见:获取“逻辑”工作目录只是查看PWD
shell变量(如果不是shell程序,则查看环境变量)。而获取“物理”工作目录仅是调用getcwd()
库函数。
使用/bin/pwd
该-L
选项时程序的操作有些微妙。它不能信任PWD
已继承的环境变量的值。毕竟,它不必由外壳程序调用,并且介入程序也可以不实施外壳程序机制,使PWD
环境变量始终跟踪工作目录的名称。或者有人可以做我刚才在那里所做的事情。
因此,它的作用是(如POSIX标准所说)检查输入的名称是否与name PWD
相同.
,这在系统调用跟踪中可以看到:
%ln -sac
%(cd b; truss / bin / pwd -L 3>&1 1>&2 2>&3 | grep -E'^ stat | __getcwd')
stat(“ / usr / home / JdeBP / b”,{ mode = drwxr-xr-x,inode = 120932,size = 2,blksize = 131072})= 0(0x0)
stat(“。”,{mode = drwxr-xr-x,inode = 120932,size = 2,blksize = 131072})= 0(0x0)
/ usr / home / JdeBP / b
%(cd b; PWD = / usr / local / etc桁架/ bin / pwd -L 3>&1 1>&2 2>&3 | grep -E'^ stat | __getcwd')
stat(“ / usr / local / etc” ,{mode = drwxr-xr-x,inode = 14835,size = 158,blksize = 10240}} = 0(0x0)
stat(“。”,{mode = drwxr-xr-x,inode = 120932,size = 2 ,blksize = 131072})= 0(0x0)
__getcwd(“ / usr / home / JdeBP / a”,1024)= 0(0x0)
/ usr / home / JdeBP / a
%(cd b; PWD = / hello /有桁架/ bin / pwd -L 3>&1 1>&2 2>&3 | grep -E'^ stat | __getcwd')
stat(“ / hello / there”,0x7fffffffe730)错误#2'没有这样的文件或目录'
__getcwd(“ / usr / home / JdeBP / a”,1024)= 0(0x0)
/ usr / home / JdeBP / a
%(cd b; PWD = / usr / home / JdeBP / c truss / bin / pwd -L 3>&1 1>&2 2>&3 | grep -E'^ stat | __getcwd')
stat(“ / usr / home / JdeBP / c“,{mode = drwxr-xr-x,inode = 120932,size = 2,blksize = 131072})= 0(0x0)
stat(”。“,{mode = drwxr-xr-x,inode = 120932 ,size = 2,blksize = 131072})= 0(0x0)
/ usr / home / JdeBP / c
%
如您所见:它仅getcwd()
在检测到不匹配时才调用;可以通过设置PWD
一个确实确实命名相同目录但使用不同路由的字符串来欺骗它。
该getcwd()
库函数是在自己的权利的主体。但是要注意:
导航到..
本身又是一个主题。另一个原则:尽管目录通常(尽管已经暗示,但这不是必需的)..
在磁盘上的目录数据结构中包含实际目录,但内核会跟踪每个目录vnode本身的父目录,因此可以导航到..
任何vnode的vnode工作目录。挂载点和更改的根机制使此操作有些复杂,这超出了此答案的范围。
在旁边
Windows NT实际上做了类似的事情。每个进程只有一个工作目录,由SetCurrentDirectory()
API调用设置,并由内核通过该目录的(内部)打开文件句柄对每个进程进行跟踪;Win32程序(不仅仅是命令解释器,而是所有 Win32程序)使用一组环境变量来跟踪多个工作目录的名称(每个驱动器一个),并在它们更改目录时追加或覆盖它们。
通常,与Unix和Linux操作系统不同,Win32程序不会向用户显示这些环境变量。但是,有时人们可以在运行于Windows NT的类Unix子系统中看到它们,也可以通过SET
以特定方式使用命令解释器的命令来看到它们。
进一步阅读