Either I've completely misunderstood something about symlinks (most likely), or their behaviour has changed at some point and I'm now catching up.
I have a script directory that resides somewhere on my file system, let's say /tmp/scripts
for the sake of this explanation. This script directory is intended be added to an arbitrary project by creating a symlink to it, within the project - e.g. ln -s /tmp/scripts $(PROJECT)/scripts
. The scripts within this directory expect to find some project-specific info in ../config
(i.e. a subdirectory of the project). However, what I'm finding is that when scripts are run from within the script directory they look in /tmp/config
(which doesn't exist) rather than $(PROJECT)/config
, resolving the relative path against the true location of the script directory, and ignoring the symlink context. This is true even though cd $(PROJECT)/scripts; pwd
shows the symlink context.
Here's a simple example of this, on Ubuntu 16.04, with 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
This surprises me, because it suggests that a process with a working directory behind a symlink does not have the same environment as the process that invoked it.
Perhaps it's always been like this? Why does the script process know that it's not really in $(PROJECT)/scripts
yet pwd
does not? Is pwd
faking it? Can anyone shed some light please?
EDIT: here's a simple practical example, that first sets up the relative directories, then creates a script (in this case a simple Makefile) and then invokes it:
#!/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
This will output 77
whereas I had hoped it that it might output 42
, as that would be the value set by the project for use by the symlinked Makefile et al. In reality, the directory b/a
doesn't actually exist, so instead:
#!/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
Resulting in:
$ ./setup
Makefile:1: ../a/Config: No such file or directory
make: *** No rule to make target '../a/Config'. Stop.
cd
is evaluated by your shell, it's not a good test case.ls
is reading the actual..
entry.make
.