pwd 和 /bin/pwd 之间的奇怪区别

use*_*976 17 shell symlink pwd

我添加了一个符号链接到当前目录ln -s . aa。如果我执行cd aa,然后我执行pwd,响应是/home/sim/aa

但是如果我执行/bin/pwd它会打印/home/sim(当前目录没有改变)。

这种差异从何而来?

cuo*_*glm 17

在包括 bash 在内的大多数 shell 中,pwd是一个内置的 shell:

$ type -a pwd
pwd is a shell builtin
pwd is /bin/pwd
Run Code Online (Sandbox Code Playgroud)

如果使用/bin/pwd,则必须使用-L选项来获得与 builtin 相同的结果pwd

$ ln -s . test
$ cd test && pwd
/home/cuonglm/test
$ /bin/pwd
/home/cuonglm
$ /bin/pwd -L
/home/cuonglm/test
Run Code Online (Sandbox Code Playgroud)

默认情况下,/bin/pwd忽略符号链接并打印实际目录。

来自info pwd

`-L'
`--logical'
     If the contents of the environment variable `PWD' provide an
     absolute name of the current directory with no `.' or `..'
     components, but possibly with symbolic links, then output those
     contents.  Otherwise, fall back to default `-P' handling.

`-P'
`--physical'
     Print a fully resolved name for the current directory.  That is,
     all components of the printed name will be actual directory
     names--none will be symbolic links.
Run Code Online (Sandbox Code Playgroud)

内置pwd默认包含符号链接,除非使用该-P选项,或者-o physical启用了 set builtin。

来自man bash

pwd [-LP]
              Print the absolute pathname of the  current  working  directory.
              The pathname printed contains no symbolic links if the -P option
              is supplied or the -o physical option to the set builtin command
              is  enabled.  If the -L option is used, the pathname printed may
              contain symbolic links.  The return status is 0 unless an  error
              occurs  while  reading  the  name of the current directory or an
              invalid option is supplied.
Run Code Online (Sandbox Code Playgroud)

  • @user3581976:你用`set -o physical`启动你的shell的图像,现在`pwd`默认使用`-P`选项,如果你没有`-L`选项,你如何打印路径包含符号链接?阅读此 `https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html` 以了解 `set -o physical` 的作用。 (2认同)

Sco*_*ott 8

进程可能会询问文件系统以确定其当前工作目录,使用的方法有点过于复杂,无法作为这个问题的答案。这就是pwd程序和getcwd库函数所做的。在 Unix 的早期,它们是找出您的工作目录的唯一方法。以下是我在其他任何答案中都找不到的问题的部分答案,甚至在本网站的其他任何地方都找不到(经过 42 秒的搜索):

  • 当 shell 启动时,它获取其当前工作目录(可能通过调用getcwd)。
  • 此后,无论何时执行 a cdpushdpopd,shell 都会使用字符串操作函数跟踪工作目录。例如,

    • 如果您的工作目录是/home/sim并且您键入cd ..,shell 会计算您的工作目录是/home
    • 如果您的工作目录是/home/sim并且您键入cd .,shell 会计算您的工作目录仍然是/home/sim
    • 如果您的工作目录是/home/sim并且您键入cd aa,shell 会计算您的工作目录/home/sim/aa– 不检查是否aa是符号链接。

    这样做是为了节省调用 的“成本” getcwd。但这是一种权衡,因为它可能导致不正确的信息。

  • pwd(内置)命令只显示shell的记忆/计算的工作目录是什么概念。
  • 此外,为了方便用户进程,shell 将其记住/计算出的工作目录的概念放入 PWD 环境变量中。如果一个过程需要准确的信息,它永远不应该依赖于此。

因此,底线是外壳可能会混淆它的位置。但是,如果您键入/bin/pwd,它将在一个单独的进程中运行,该进程无权访问 shell 的工作目录概念,因此它确定了真正的工作目录本身,这是老式的方式。(例外:/bin/pwd程序可以查看 PWD 环境变量,显然当您指定-L.时它会查看。)这是外壳如何混淆的另一个示例:

cd /home/sim/aa # 假设/home/home/sim/home/sim/aa
# 都是真正的目录(而不是符号链接)。
pwd # 输出:/home/sim/aa,这是正确的。
mv ../aa ../bb
pwd # 输出:/home/sim/aa,这是不正确的。
/bin/pwd # 输出:/home/sim/bb,这是正确的。


并且,如果您对此不清楚,如果您输入ln -s . aacd aa,那么您当前的工作目录并没有改变,就像您输入时一样cd .——因为,这本质上就是您在输入时所做的cd aa

  • 这个答案似乎有点*弯曲*。`-L` 不仅仅是*节省成本* - 并且 `$PWD` 是用户定义的 POSIX 指定的环境变量 - 用户空间应用程序应该*信任它* *(无论这意味着什么......?)* . 无论如何,虽然我根本不喜欢符号链接,但用户有权在他或她应该选择的尽可能多的疯狂方向上进行间接操作——这就是 `-L` 最重要的地方。 (2认同)