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)" ]
    if ! cd -- "${PWD}" >/dev/null 2>&1
      echo "W: ${PWD} does not exist anymore"
      return 1

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.)

Comments (4)

First of all there's a stat module to spare you the linker call.

Second, [ . -ef $PWD ] should really do the same too.

Nov. 19, 2009, 1:57 p.m. #
Sweet, thanks. Although, I think we want "! [ . -ef $PWD ]" instead.
Daniel Jacobowitz

You have completely made my day, sir! Our test scripts remove and recreate the test directory, and it drives me nuts to have to cd $PWD all the time. Yet somehow I never thought of automating it.

Nov. 19, 2009, 3:19 p.m. #

Nice handling of this absurdity. I use 'cd .' all the time even if I thought at first it was a command with absolutely no interest. One reason is to update my xterm title (which is only updated when I cd). The second is this exact situation.

Nov. 19, 2009, 6:11 p.m. #

Cost of stat totally not worth it in DCS. sadface.

Nov. 19, 2009, 6:40 p.m. #