为什么反向遍历符号链接的相对路径会使用真实路径进行解析?

为什么反向遍历符号链接的相对路径会使用真实路径进行解析?

要么我完全误解了有关符号链接的某些内容(很可能),要么它们的行为在某个时刻发生了变化,而我现在正在赶上。

我的文件系统上有一个脚本目录,/tmp/scripts为了便于说明。该脚本目录旨在通过在项目内创建符号链接来添加到任意项目 - 例如ln -s /tmp/scripts $(PROJECT)/scripts.该目录中的脚本期望在../config(即项目的子目录)中找到一些特定于项目的信息。然而,我发现的是当脚本从脚本目录中运行时他们查看/tmp/config(不存在)而不是$(PROJECT)/config,解决相对路径真的脚本目录的位置,并忽略符号链接上下文。即使cd $(PROJECT)/scripts; pwd显示符号链接上下文也是如此。

这是一个在 Ubuntu 16.04 上使用 Bash 4.3.48 的简单示例:

$ mkdir a
$ touch a/apples
$ mkdir -p b/a
$ touch b/a/bananas
$ mkdir -p b/c
$ ln -s b/c c
$ cd c
$ pwd
/home/user/c      # note this does not show '/home/user/b/c'
$ ls ../a
bananas
$ cd ../a
$ ls
apples

这让我感到惊讶,因为它表明符号链接后面有工作目录的进程与调用它的进程没有相同的环境。

也许一直都是这样?为什么脚本进程知道它还没有真正$(PROJECT)/scripts进入pwd?是pwd造假吗?有人可以解释一下吗?

编辑:这是一个简单的实际示例,首先设置相对目录,然后创建一个脚本(在本例中是一个简单的 Makefile),然后调用它:

#!/bin/bash
mkdir -p a
echo "A:=42" > a/Config
mkdir -p b/a
echo "A:=77" > b/a/Config
mkdir -p b/c
ln -sfn b/c c
echo -e "include ../a/Config\nall:\n\t@echo \${A}" > c/Makefile
cd c
make

这将输出77,而我希望它可能输出42,因为这将是项目设置的值,供符号链接的 Makefile 等使用。实际上,该目录b/a实际上并不存在,因此:

#!/bin/bash
mkdir -p a
echo "A:=42" > a/Config
mkdir -p b/c
ln -sfn b/c c    
echo -e "include ../a/Config\nall:\n\t@echo \${A}" > c/Makefile    
cd c
make

导致:

$ ./setup
Makefile:1: ../a/Config: No such file or directory
make: *** No rule to make target '../a/Config'.  Stop.

答案1

如果您想cd按预期行事,请致电:

cd -P c

并将pwd打印:

/home/user/b/c

您所看到的问题是由于您的 shell 遵循了不满意的 POSIX 决定并采用了cd -L默认值而导致的。这使得 shell 记住明显的$PWD /home/user/c.由于 shell 命令cd ..不会调用chdir(".."),而是将$PWD值缩短一个元素,然后chdir()转到该缩短的路径,cd ..从而使您从原来的位置返回。

这是一个安全风险,因为人们倾向于运行例如:

ls ../

对结果感到满意后,可以运行:

cd ../; rm *.c

并删除与预期不同的文件。

请注意,POSIX 默认值是根据默认行为建模的,ksh88同时当 ksh 引入该默认行为时,AT&T 决定cd -P在 Bourne Shell 中将更安全的变体实现为默认行为。

相关内容