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.
@hrj As said earlier -
cat myFile
is correct, since the file still belongs to the inode.Think of it as this:
Your create the folder
xyz
, which is represented in the filesystem as this:Then you run
mv /path/to/xyz /new/path
, which changes the entry to this:Your first terminal still holds the old path as
$PWD
, but is still referencing that inode with idinodeId1
- even though it now has a new path-entry. When you runcat myFile
it will look for a fitting inode listed in the contents-entry of its current inode (if you run e.g. vim on the file and inside of itecho expand('%:p')
to expand and echo the path it will most likely show/new/path/myFile
).I don't know why your builtin
pwd
is returning the old status, but I'd create an issue for that or ask the maintainer of your package about it.