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. – Michael Homer Jun 21 '18 at 00:06make
. – davidA Jun 21 '18 at 02:06scripts
directory, since that's what's manifesting the problem, rather than a replication script (the original block was mostly fine for that). In particular the element that when scripts are run from within the script directory you see the problem would highlight more clearly what's happening with an actual example. – Michael Homer Jun 21 '18 at 02:41