+- somedir/
   +- symlink/  -> /some_other_dir

This command (in addition to my Makefiles) fails:

cd /base/symlink
ls ../somedir

Bash complains that ../somedir does not exist. Likewise, my makefiles in some_other_dir that reference ../somedir fail. However, cd .. works just as expected. Can I have my shell act with regards to the logical structure?

  • 2
    You mean cd ../somedir works, while ls ../somedir does not, right? I could reproduce this behavior. – Bernhard Jan 16 '13 at 15:11
  • @Bernhard: that is correct. This also breaks some more complex commands in my Makefile. – Atilla Filiz Jan 16 '13 at 15:46
  • sure you don't have a broken symlink. This workflow fine on my system. Did I get your example correct? [code] /tmp # ls -ld {bob,tom} drwxr-xr-x 3 scott scott 4.0K Jan 16 12:29 bob lrwxrwxrwx 1 scott scott 3 Jan 16 12:29 tom -> bob /tmp # cd tom /tmp/tom # ls dir file /tmp/tom # ls ../bob dir file [/code] – frogstarr78 Jan 16 '13 at 20:32

.. is a directory entry in the current directory. It is a hardlink to the directory one level up. /base/symlink/.. is actually the same file as /some_other_dir/.., and it is / (unless some_other_dir is itself also a symlink to somewhere else).

In most shells, cd treats .. specially, that is instead of treating it as the .. directory entry, occurrences of .. are interpreted by cd (and not by the system's pathname resolution) as removing one level of directory.

As an example, in cd a/b/.., the shell does a chdir("a") instead of doing a chdir("a/b/.."). To get the latter, you need to do cd -P a/b/...

It's important to realise that it only applies to cd (and only in some shells), (IMO, a misfeature), not to ls or vi or anything else (unless that anything else is a script of those shells that passes those paths to cd without -P).

In those shells where cd does that logical interpretation of .., the pwd builtin and the $PWD variable contain the logical current directory instead of the real (physical) one, that is one with possibly symlink directory components. Similarly, you can use pwd -P to get the physical working directory.

Now, if you want to do

cd /A/b
anything-but-cd ../c

And actually mean:

anything-but-cd /A/c

Regardless of whether /A/b was a symlink or not, you could do instead:

anything-but-cd "$(dirname -- "$PWD")/c"


anything-but-cd "${PWD%/*}/c"

Or with zsh:

anything-but-cd $PWD:h/c

To remove 3 /*s off the end of $PWD:

anything-but-cd "${PWD%/*/*/*}/c" # POSIX
anything-but-cd $PWD:h:h:h/c      # zsh
  • Could somebody explain / link what the PWD%/* means? — dirname -- "$PWD" is clear enough, but it only helps when the lowermost directory is symlinked. If I'm in rd/sl/rd/rd and would like to get out, I would need to know exactly at which level the symlink is and explicitly treat that, whereas cd ../../../.. does that automatically. – leftaroundabout Nov 3 '20 at 9:11
  • @leftaroundabout, run info bash param for instance. To get to the section about parameter expansion in the bash manual. To strip more than one /* from the end of $PWD, you can do ${PWD%/*/*/*} (here for 3). Or in zsh/csh: $PWD:h:h:h – Stéphane Chazelas Nov 3 '20 at 9:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.