Chris Lamb

Transparent directory replacement with zsh

Under UNIX, it is possible to get into a position where your shell's working directory is pointing to an inode that no longer exists, but a "newer" directory with the same name exists.

The easiest way of reproducing this scenario is as follows:

$ cd $(mktemp -d)
$ rm -rf $PWD
$ mkdir $PWD

However, as a concrete example, imagine you are debugging something deep inside a generated code tree — if you ran make clean and then make again from another shell, your debugging shell would be left pointing to an inode that does not exist (as it was removed by make clean), yet the make call would have made an identically named directory in its place.

Shells behave rather unintuitively in this situation; ls will (correctly) return no results, but attempting to do anything useful results in curious error messages.

I use the following zsh precmd hook to transparently fix this for me:

precmd () {
  # "DOS emulation mode"
  if [ "$(stat -c %i . 2>/dev/null)" != \
                 "$(stat -c %i -- "${PWD}" 2>/dev/null)" ]
  then
    OLDOLDPWD="${OLDPWD}"
    if ! cd -- "${PWD}" >/dev/null 2>&1
    then
      echo "W: ${PWD} does not exist anymore"
      return 1
    fi
    OLDPWD="${OLDOLDPWD}"
  fi
}

The cost of the stat calls seem justified by the convenience and are in any case insignificant compared to the other things I am doing in my precmd. If you are using zmodload zsh/stat, then replace stat -c %i with stat +inode.

(My previous experience with zsh tricks is that the functionality invariably exists already in some obscurely named builtin. Here's hoping.)


Chris Lamb is a freelance software developer and the current Debian Project Leader. You can read other posts by me, see software I have written or read more about me. You can also follow me @lolamby.


Tags: Hacks GNU/Linux

Planets: WUGLUG UWCS Debian ALUG

Thursday 19th November 2009


Four comments