假设我登录到 unix 系统上的 shell 并开始窃听命令。我最初从用户的主目录开始~。我可能会从那里cd到目录Documents。
这里更改工作目录的命令非常简单直观地理解:父节点有一个它可以访问的子节点列表,并且大概它使用搜索的(优化的)变体来定位子节点的存在输入用户的名称,然后“更改”工作目录以匹配此名称 - 如果我错了,请纠正我。更简单的是,shell 只是“天真地”尝试完全按照用户的意愿尝试访问目录,并且当文件系统返回某种类型的错误时,shell 会相应地显示响应。
然而,我感兴趣的是,当我向上导航一个目录时,相同的过程是如何工作的,即导航到父级或父级的父级。
鉴于我未知的,大概是“盲”位置Documents,整个文件系统树中可能有许多目录之一具有该名称,Unix 如何确定我接下来应该放置的位置?它是否参考pwd并检查了它?如果是,如何pwd跟踪当前导航状态?
Jde*_*eBP 77
其他答案过于简单化,每个答案都只展示了故事的一部分,并且在几点上是错误的。
有两种跟踪工作目录的方式:
chdir()和fchdir()系统调用设置,后者由chroot()。人们可以/proc在 Linux 操作系统上或通过fstatFreeBSD 等上的命令间接看到它们:% fstat -p $$|head -n 5 USER CMD PID FD MOUNT INUM MODE SZ|DV R/W 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 中,数据结构在应用程序空间中,但保持对这些目录的开放引用的原则保持不变。
chdir()。如果更改为相对路径名,它会操作字符串以附加该名称。如果更改为绝对路径名,它将用新名称替换该字符串。在这两种情况下,调整串删除.和..组件和追逐符号链接与其链接到的名称替换它们。(例如,这是 Z shell 的代码。)
内部字符串变量中的名称由命名的shell 变量PWD(或cwd在 C shell 中)跟踪。这通常作为环境变量(名为PWD)导出到 shell 生成的程序。
这两种跟踪事物的方法是通过shell 内置命令的-P和-L选项cd以及pwdshell 的内置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/there /bin/pwd -L) /usr/home/JdeBP/a %
如您所见:获取“逻辑”工作目录是查看PWDshell变量(如果不是shell程序,则为环境变量)的问题;而获取“物理”工作目录是调用getcwd()库函数的问题。
使用/bin/pwd该-L选项时程序的操作有些微妙。它不能信任PWD它继承的环境变量的值。毕竟,它不需要被 shell 调用,而且中间程序可能没有实现 shell 使PWD环境变量始终跟踪工作目录名称的机制。或者有人可能会做我刚才在那里做的事情。
所以它所做的是(如 POSIX 标准所说)检查给出的名称是否与 namePWD产生相同的内容.,如系统调用跟踪所示:
% 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 truss /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/there truss /bin/pwd -L 3>&1 1>&2 2>&3 | grep -E '^stat|__getcwd')
stat("/hello/there",0x7fffffffe730) ERR #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()库函数是在自己的权利的主体。但具体来说:
..。当它到达..与其工作目录相同的循环或尝试打开下一个时出现错误时,它停止..。这将是大量的系统调用。但是,请注意,即使在 FreeBSD 和其他操作系统上,内核也不会使用字符串跟踪工作目录。
导航到..本身又是一个主题。另一个原则:虽然传统上的目录(虽然,正如已经提到的,这不是必需的)..在磁盘上的目录数据结构中包含一个实际的目录,但内核会跟踪每个目录 vnode 本身的父目录,因此可以导航到..任何目录的 vnode工作目录。挂载点和更改的根机制使这有些复杂,这超出了本答案的范围。
Windows NT 实际上做了类似的事情。每个进程有一个工作目录,由SetCurrentDirectory()API 调用设置并由内核通过该目录的(内部)打开文件句柄跟踪每个进程;Win32 程序(不仅仅是命令解释器,而是所有Win32 程序)使用一组环境变量来跟踪多个工作目录(每个驱动器一个)的名称,在它们更改目录时附加或覆盖它们。
通常,与 Unix 和 Linux 操作系统的情况不同,Win32 程序不会向用户显示这些环境变量。但是,有时可以在运行在 Windows NT 上的类 Unix 子系统中看到它们,也可以通过SET以特定方式使用命令解释器的命令来看到它们。
pwd”。 开放组基本规范第 7 期。IEEE 1003.1:2008。开放组。2016 年。| 归档时间: |
|
| 查看次数: |
3424 次 |
| 最近记录: |