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


15

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

但是,如果执行/bin/pwd该命令,它将打印/home/sim(当前目录未更改)。

这种差异从何而来?

Answers:


17

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

$ type -a pwd
pwd is a shell builtin
pwd is /bin/pwd

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

$ ln -s . test
$ cd test && pwd
/home/cuonglm/test
$ /bin/pwd
/home/cuonglm
$ /bin/pwd -L
/home/cuonglm/test

默认情况下,/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.

内置pwd默认情况下包括符号链接,不同之处在于-P使用了该选项或-o physical启用了内置设置。

来自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.

我不确定这些差异的来源是什么
user3581976

/bin/pwd默认情况下忽略符号链接,请阅读info pwd我的答案:为当前目录打印一个完全解析的名称。也就是说,打印名称的所有组成部分将是实际目录名称- 没有一个将是符号链接。
cuonglm

@ user3581976:请参阅我的更新内容,以更清楚地了解。
cuonglm 2014年

尽管默认情况下设置了pwd的-L命令,为什么呢?外壳程序不使用/ bin / pwd命令运行pwd吗?
user3581976

2
@ user3581976:您使用开始的shell图像set -o physical,现在默认情况下pwd是use -P选项,如果没有-L选项,如何打印包含符号链接的路径?阅读此内容https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html以了解set -o physical功能。
cuonglm

7

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

  • 当shell启动时,它将获取其当前的工作目录(可能通过调用getcwd)。
  • 此后,只要你做了cdpushdpopd,外壳跟踪使用字符串处理函数的工作目录。例如,

    • 如果您的工作目录是 /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,它将在一个单独的进程中运行,而该进程无法访问外壳程序关于工作目录的概念,因此它可以确定老式的工作目录本身。(例外:该/bin/pwd程序可以查看PWD环境变量,并且当您指定时显然也可以-L。)这是另一个如何使Shell感到困惑的示例:

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 . aaand cd aa,那么您当前的工作目录不会发生变化,与您键入时所做的一样多,cd .因为,这实际上是您键入时所做的cd aa


谢谢,很好的答案,这是我一直在等待;)
user3581976

2
这个答案似乎有点弯曲-L除了节省成本之外,还有很多事情 -并且$PWD是用户定义的POSIX指定的环境变量-用户空间应用程序可能应该信任它 (这意味着...?)。无论如何,尽管我根本不喜欢符号链接,但用户有特权在许多疯狂的方向上进行间接操作,而这些方向应该由他或她选择,这-L是最重要的。
mikeserv

1
这应该是公认的答案(符号链接不是问题的重点)。
Thomas Dickey
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.