/tmp
假设我在Calledparent
和中创建了两个文件夹child
。child
包含一个名为 的文件test-child.txt
,并parent
包含一个名为 的文件test-parent.txt
。现在让我们进入parent
并创建一个到 的符号链接child
。接下来,进入child
并尝试test-parent.txt
从复制parent
。 bash 完成工作正常,但实际文件复制失败 --
cd /tmp
pwd
/tmp
mkdir parent
mkdir child
touch child/test-child.txt
ls child/
test-child.txt
cd parent
ln -sf ../child .
touch test-parent.txt
cd child
cp ../test-parent.txt .
cp: cannot stat ‘../test-parent.txt’: No such file or directory
为什么 ??
而且,当我在里面时child
,如果我说——
pwd
/tmp/parent/child
答案1
Shell 会跟踪符号链接以方便用户。这具有cd foo && cd ..
始终返回到原始目录的良好效果,即使foo
是指向目录的符号链接也是如此。它有两个缺点:主要的一个是其他程序不这样做;另一个缺点是其他程序不这样做。此外,符号目录跟踪引入了其自身的问题(当符号链接更改时会发生什么?如果进程没有读取符号链接的权限会发生什么?等等)。
Shell 只能做到这一点,因为它们会跟踪所有目录更改,因此它们会记住您是如何到达那里的。当新进程启动时,它不会获取此历史信息。在幕后,它通过从当前目录向上移动、跟踪..
链接直到到达根目录来找到它所在的位置。
如果您通过符号链接到达目录,则可以使用以下命令打印出无符号链接的路径pwd
内置的,通过调用pwd -P
.如果您从 shell 调用另一个程序,请勿向其传递包含..
符号链接组件的路径,因为该程序会对它进行不同的解释。相反,..
通过调用消除组件pwd -P
:
cp "$(cd .. && pwd -P && echo /)test-parent.txt" .
如果您想忘记cd
shell 会话中过去命令中使用的符号链接,您可以运行
cd "$(pwd -P && echo /.)"
这会更改为当前目录,因此它不会有效地更改 shell 进程的当前目录,但会更改 shell 跟踪的当前目录的路径,使其成为无符号链接。
1这就是getcwd
呼叫的传统运作方式。某些内核确实会跟踪当前目录,但不跟踪符号链接,如果没有其他原因,则为了向后兼容(但也因为符号链接的微妙边缘情况)。
答案2
这是因为cp
你的 shell 玩的不是同一个链接游戏。您的 shell 正在跟踪当前工作目录的链接,作为当前工作目录的间接访问,但是当 shell 调用时,内核不希望出现任何废话cp
- 相反,内核将创建 的cp
当前工作目录一个完全限定的绝对路径 - 因此它的.
链接和你的 shell 的.
链接是不一样的.
。
您可以轻松确保当前工作目录的绝对路径,cd -P .
并且同样适用于任何其他目录,例如cd -P -- /any/other/directory
.你可以至少用于打印likepwd
的绝对路径,并且在许多 shell 中它也会更改为绝对路径.
pwd -P
$PWD
(以同样的方式cd -P .
)。
例如:
cd /tmp
mkdir -p parent child
cd parent
ln -s ../child child
touch ./child/somefile
cd -L child ###the default
printf %s\\n "$PWD"/*
cd -P .
printf %s\\n "$PWD"/*
输出
/tmp/parent/child/somefile
/tmp/child/somefile