AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 413204
Accepted
marked-down
marked-down
Asked: 2017-12-27 19:50:57 +0800 CST2017-12-27 19:50:57 +0800 CST 2017-12-27 19:50:57 +0800 CST

Unix 在浏览文件系统时如何跟踪用户的工作目录?

  • 772

假设我登录到 unix 系统上的 shell 并开始敲击命令。我最初从用户的主目录开始~。我可能会从那里cd下到目录Documents。

这里更改工作目录的命令非常简单直观地理解:父节点有一个它可以访问的子节点列表,并且大概它使用搜索的(优化的)变体来定位子节点的存在用户输入的名称,然后“更改”工作目录以匹配此 - 如果我在那里错了,请纠正我。甚至更简单的是,shell 只是“天真地”尝试完全按照用户的意愿访问目录,并且当文件系统返回某种类型的错误时,shell 会相应地显示响应。

然而,我感兴趣的是,当我向上导航目录时,相同的过程是如何工作的,即到父级或父级的父级。

鉴于我未知的,可能是“盲”的位置Documents,可能是整个文件系统树中具有该名称的多个目录之一,Unix 如何确定我接下来应该放在哪里?它是否参考pwd并检查了它?如果是,如何pwd跟踪当前的导航状态?

filesystems pwd
  • 3 3 个回答
  • 3778 Views

3 个回答

  • Voted
  1. Best Answer
    JdeBP
    2017-12-28T00:20:40+08:002017-12-28T00:20:40+08:00

    其他答案过于简单化,每个都只呈现故事的一部分,并且在几点上是错误的。

    有两种方法可以跟踪工作目录:

    • 对于每个进程,在表示该进程的内核空间数据结构中,内核存储两个 vnode 引用,指向该进程的工作目录和根目录的 vnode。前一个引用由chdir()andfchdir()系统调用设置,后者由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 中,数据结构位于应用程序空间中,但保持对这些目录的开放引用的原则保持不变。

    • 在内部,在诸如 Z、Korn、Bourne Again、C 和 Almquist shell 等 shell 中,shell还使用内部字符串变量的字符串操作来跟踪工作目录。只要有理由调用它就会这样做chdir()。

      如果更改为相对路径名,它会操纵字符串以附加该名称。如果更改为绝对路径名,它会将字符串替换为新名称。在这两种情况下,它都会调整字符串以删除.和..组件,并追踪符号链接,用它们的链接名称替换它们。(例如,这是 Z shell 的代码。)

      内部字符串变量中的名称由名为(或在 C shell 中)的shell 变量跟踪。这通常作为环境变量(名为)导出到由 shell 生成的程序。PWDcwdPWD

    这两种跟踪事物的方法由和 shell 内置命令的-Pand-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;密码=/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",0x7ffffffffe730) 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 ,大小=2,blksize=131072 }) = 0 (0x0)
    /usr/home/JdeBP/c
    %

    如您所见:它仅getcwd()在检测到不匹配时调用;并且可以通过设置PWD一个确实命名相同目录但路径不同的字符串来欺骗它。

    库getcwd()函数本身就是一个主题。但具体来说:

    • 最初它纯粹是一个库函数,它通过反复尝试在目录中查找工作目录来建立从工作目录到根目录的路径名..。当它到达..与其工作目录相同的循环或尝试打开下一个错误时,它会停止..。这将是大量的系统调用。
    • 现在的情况稍微复杂一些。例如,在 FreeBSD 上(对于其他操作系统也是如此),它是一个真正的系统调用,正如您在前面给出的系统调用跟踪中看到的那样。从工作目录 vnode 到根目录的所有遍历都是在单个系统调用中完成的,这利用了内核模式代码对目录条目缓存的直接访问等优势,可以更有效地进行路径名组件查找。

      但是,请注意,即使在 FreeBSD 和其他操作系统上,内核也不会使用字符串跟踪工作目录。

    导航到..本身又是一个主题。另一个概要:虽然目录通常(尽管已经提到,这不是必需的)在磁盘上的目录数据结构中包含实际..的目录数据结构,但内核跟踪每个目录 vnode 本身的父目录,因此可以导航到..任何 vnode工作目录。挂载点和更改的根机制有些复杂,这超出了此答案的范围。

    在旁边

    Windows NT 实际上做了类似的事情。每个进程有一个工作目录,由SetCurrentDirectory()API 调用设置,并由内核通过该目录的(内部)打开文件句柄跟踪每个进程;并且有一组环境变量,Win32 程序(不仅是命令解释器,而是所有Win32 程序)使用来跟踪多个工作目录的名称(每个驱动器一个),在它们更改目录时附加或覆盖它们。

    通常,与 Unix 和 Linux 操作系统不同,Win32 程序不会向用户显示这些环境变量。但是,有时可以在 Windows NT 上运行的类 Unix 子系统中看到它们,也可以通过以SET特定方式使用命令解释器的命令来看到它们。

    进一步阅读

    • “ pwd”。 开放组基本规范第 7 期。IEEE 1003.1:2008。公开组。2016 年。
    • “路径名解析”。 开放组基本规范第 7 期。IEEE 1003.1:2008。公开组。2016 年。
    • https://askubuntu.com/a/636001/43344
    • unix下文件是怎么打开的?
    • 什么是 inode,在 FreeBSD 或 Solaris 中
    • Cygwin中奇怪的环境变量!::=::\
    • 为什么 CDPATH 不能按照手册中的说明工作?
    • 如何设置 zsh 以使用物理路径?
    • 进入通过链接链接的目录
    • 79
  2. Johan Myréen
    2017-12-27T23:03:07+08:002017-12-27T23:03:07+08:00

    内核不跟踪目录或文件名;文件或目录在内核中由 inode/device 对表示。chdir()像,等系统调用open()将路径作为参数,它可以是绝对路径(例如/etc/passwd),也可以是相对于当前目录的路径(例如:Documents, ..)。当进程执行chdir("Documents")时,会在当前工作目录中进行查找Documents,并更新进程的工作目录以引用该目录。从内核的角度来看,名称“..”没有什么特别之处,它只是文件系统中..引用父目录的约定。

    该getcwd()函数不是系统调用,而是一个库函数,它必须一直运行到根目录,并在途中记录路径组件的名称。

    • 1
  3. user267857
    2017-12-29T04:46:09+08:002017-12-29T04:46:09+08:00

    有趣的是,传统cd ..上比pwd. 命名..的目录被明确地放置在文件系统中。系统跟踪当前目录的设备/inode,所以cd ..或更准确地说,系统调用chdir("..")只需要在属于当前目录的inode的文件中查找名称“..”并将当前目录的设备/inode更改为在那里找到的价值。

    pwd(更准确地说/bin/pwd)..依次跟随链接并读取相应的目录,直到找到它来自的 inode,反向组装这些名称的列表,直到它到达根目录(特别是不包含..条目)。

    现在这是原始的低级基本行为。相反,实际的 shell 命令pwd依赖于各种缓存当前路径名的技术。但在核心,只有它的 inode 才是真正已知的。这意味着一旦使用符号链接来导航目录,当前 shell 和系统的当前工作目录名称概念/bin/pwd可能会有所不同。

    • 0

相关问题

  • 我应该在 NAS 的 SD 卡中使用哪个文件系统?

  • 如何提前知道 .zip 内部是否有父目录

  • Virtualbox 动态分配磁盘 *.vdi 不断增长

  • du/df 和 ls 报告不同的磁盘使用情况

  • Linux 内核开发人员如何处理数百万行代码的工作?他们是一种方法吗?[关闭]

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    JSON数组使用jq来bash变量

    • 4 个回答
  • Marko Smith

    日期可以为 GMT 时区格式化当前时间吗?[复制]

    • 2 个回答
  • Marko Smith

    bash + 通过 bash 脚本从文件中读取变量和值

    • 4 个回答
  • Marko Smith

    如何复制目录并在同一命令中重命名它?

    • 4 个回答
  • Marko Smith

    ssh 连接。X11 连接因身份验证错误而被拒绝

    • 3 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Marko Smith

    systemctl 命令在 RHEL 6 中不起作用

    • 3 个回答
  • Marko Smith

    rsync 端口 22 和 873 使用

    • 2 个回答
  • Marko Smith

    以 100% 的利用率捕捉 /dev/loop -- 没有可用空间

    • 1 个回答
  • Marko Smith

    jq 打印子对象中所有的键和值

    • 2 个回答
  • Martin Hope
    EHerman JSON数组使用jq来bash变量 2017-12-31 14:50:58 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Drux 日期可以为 GMT 时区格式化当前时间吗?[复制] 2017-12-26 11:35:07 +0800 CST
  • Martin Hope
    AllisonC 如何复制目录并在同一命令中重命名它? 2017-12-22 05:28:06 +0800 CST
  • Martin Hope
    Steve “root”用户的文件权限如何工作? 2017-12-22 02:46:01 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST
  • Martin Hope
    Cbhihe 将默认编辑器更改为 vim for _ sudo systemctl edit [unit-file] _ 2017-12-03 10:11:38 +0800 CST
  • Martin Hope
    showkey 如何下载软件包而不是使用 apt-get 命令安装它? 2017-12-03 02:15:02 +0800 CST
  • Martin Hope
    youxiao 为什么目录 /home、/usr、/var 等都具有相同的 inode 编号 (2)? 2017-12-02 05:33:41 +0800 CST
  • Martin Hope
    user223600 gpg —list-keys 命令在将私钥导入全新安装后输出 uid [未知] 2017-11-26 18:26:02 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve