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.
access(2)
is not very granular, so the solution typically involves writing something to iterate and test each path element in turn...