When you are in a shell in Linux, you may be led to believe you are in directory
xyz
but might actually be in directorypqr
.
In a terminal,
cd /tmp
mkdir xyz
cd xyz
echo Hi from terminal 1 > myFile
Now keeping this terminal open, spawn a new terminal window and in the new terminal,
cd /tmp
mv xyz pqr
The path /tmp/xyz
is not valid any more. The file /tmp/xyz/myFile
has been now moved to /tmp/pqr/myFile
. All fine so far, but ...
Go back to the first terminal and type:
$ pwd
/tmp/xyz
$ cat myFile
Hi from terminal 1
Whoa! What just happened?
The shell reports you are in /tmp/xyz
. But when you read the file with a relative path (myFile
), it actually reads /tmp/pqr/myFile
.
I got severely burnt by this today, so let me provide that as an example.
I have a directory where I keep some old data (which happens to be a FoxPro database). This data is then consumed by an application written in Scala. And this setup has been stable for several months now.
But today, I acquired a new snapshot of the data. So I moved the existing directory (xyz) to a new location (pqr), and unzipped the new snapshot into my standard directory location (xyz). However, the terminal where I ran the application from, was not closed. Its pwd
showed xyz
, but it now picked its data from pqr
.
To cut a long story short: Chaos ensued! The application was now showing old data, which I interpreted to be either an in-memory corruption or a database corruption. To fix this, I peeled away several layers of the application, and finally ended up debugging the database driver! It was only after exhausting all possibilities, that I had a brain wave to check the md5sum of the data and that's when the penny fell.
Here's a simple fix. It's for zsh, but you should be able to easily adapt it to other shells.
You just need to add these lines to your ~/.zshrc
:
_pwd_alias_hell () {
if [[ `readlink -f ./` != `readlink -f $(pwd)` ]] then;
echo You are in pwd alias hell!
echo "pwd =" `pwd`
echo "actual pwd =" `readlink -f ./`
fi
}
autoload add-zsh-hook
add-zsh-hook precmd _pwd_alias_hell
Now whenever you run a command in the shell or simply press Enter
, the above function will check the pwd
and raise an alert when it has been aliased.
The above function is intentionally bare, to help you see how it works. You can style it, to make the alert message more prominent, like so:
_pwd_alias_hell () {
if [[ `readlink -f ./` != `readlink -f $(pwd)` ]] then;
echo $fg_bold[red]You are in pwd alias hell!$reset_color
echo "pwd =" $fg_bold[blue]`pwd`$reset_color
echo "actual pwd =" $fg_bold[blue]`readlink -f ./`$reset_color
fi
}
autoload add-zsh-hook
add-zsh-hook precmd _pwd_alias_hell
- The solution was updated a bit. The earlier check was:
if [[ `readlink -f ./` != `pwd` ]] then;
but that threw up false negatives for symlinked directories. The new test is more robust.
It would be a lot worse if ext4 wouldn't identify items in your filesystem by their inodes but by their path instead. NTFS is using paths to identify files. One particularly bad thing about this is that you can create a file
x
and give it certain pemissions - you move it away and create a new filex
. Guess which permissions newx
now has.Yup, the ones you gave old
x
instead of the default.That's a bit confusing. Are you referring to
pwd
(the builtin),pwd
(the program), what your shell shows for%~
in your prompt or the environment variable$PWD
- both$PWD
and%~
are not being updated unless you change your directories[1].pwd
the zsh builtin shows the correct entry from the inode - dunno about the programpwd
though. It might be wrong since it officially just reads$PWD
.In other words: Your fix wouldn't work - you'd need to use
$PWD
instead ofpwd
.[1]: from the man page:
PWD The present working directory. This is set when the shell initializes and whenever the directory changes.