How can I find the first missing directory in a long path?

One of my favourite utilties is namei, part of util-linux and hence generally present only on Linux:

$ namei /usr/share/foo/bar
f: /usr/share/foo/bar
 d /
 d usr
 d share
   foo - No such file or directory

But its output is not very parseable. So, if you just wish to point out something is missing, namei might be useful.

It's useful for troubleshooting general problems in accessing a path, since you can get it to state whether a component is a link or a mount point, as well as its permissions:

$ ln -sf /usr/foo/bar /tmp/
$ namei -lx /tmp/bar
f: /tmp/bar
Drwxr-xr-x root    root    /
Drwxrwxrwt root    root    tmp
lrwxrwxrwx muru    muru    bar -> /usr/foo/bar
Drwxr-xr-x root    root      /
drwxr-xr-x root    root      usr
                             foo - No such file or directory

The capital D indicates a mount point.


Given a canonical pathname, such as yours, this will work:

set -f --; IFS=/
for p in $pathname
do    [ -e "$*/$p" ] || break
      set -- "$@" "$p"
done; printf %s\\n "$*"

That prints through the last fully existing/accessible component of $pathname, and puts each of those separately into the arg array. The first nonexistent component is not printed, but it is saved in $p.

You might approach it oppositely:

until cd -- "$path" && cd -
do    case   $path  in
      (*[!/]/*)
              path="${path%/*}"
;;    (*)   ! break
      esac
done  2>/dev/null   && cd -

That will either return appropriately or will pare down $path as needed. It declines to attempt a change to /, but if successful will print both your current working directory and the directory to which it changes to stdout. Your current $PWD will be put in $OLDPWD as well.