我添加了一个到当前目录的符号链接ln -s . aa
。如果我执行cd aa
,然后执行pwd
,响应是/home/sim/aa
.
但是如果我执行/bin/pwd
它会打印/home/sim
(当前目录没有更改)。
这种差异从何而来?
答案1
在包括 bash 在内的大多数 shell 中,pwd
都有一个内置的 shell:
$ type -a pwd
pwd is a shell builtin
pwd is /bin/pwd
如果使用/bin/pwd
,则必须使用该-L
选项才能获得与builtin相同的结果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.
答案2
进程可以询问文件系统以确定其当前工作目录,使用的方法有点过于复杂,无法作为该问题的答案。这就是pwd
程序和getcwd
库函数的作用。在 Unix 的早期,它们是查找工作目录的唯一方法。以下是您的问题的部分答案,我在任何其他答案中都找不到,甚至在本网站的其他任何地方都找不到(经过 42 秒的搜索):
- 当 shell 启动时,它会获取当前工作目录(可能通过调用
getcwd
)。 此后,每当您执行
cd
、pushd
、 或 时popd
,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 环境变量中,以便方便用户进程。如果一个进程需要准确的信息,那么它永远不应该依赖于此。
因此,最重要的是 shell 可能会对其位置感到困惑。但是,如果您输入/bin/pwd
,它将在一个单独的进程中运行,该进程无法访问 shell 的工作目录概念,因此它会以老式的方式确定真正的工作目录本身。 (例外:/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 . aa
and cd aa
,那么您当前的工作目录没有改变,比您键入时所做的更多cd .
- 因为,这本质上就是您在键入 时所做的事情cd aa
。