Moderators: THIS IS NOT A DUPLICATE!!!! Please remove the duplicate mark.

The answers linked to do not, actually, answer my question, the way the accepted answer does. Google only points at the other answers, which are not actually answer to this particular question.

When following a symbolic link to a directory, the bash shell kind-of tries to make the illusion that the symbolic link is a real directory. However, there are many cases where this breaks down. For example, consider that I might have:


then, I have a symlink in my home directory:

ln -s /usr/local/src/project-a-1.0 ~/project

Now, I want to short-cut to work with project-a:

cd ~/project

So far, so good -- but bash pretend that I'm actually in ~/project, not in the actual working directory. It even pretend when using the pwd built-in, but of course not when using the /bin/pwd executable.

Now, if I want to check out a file in project-b, I might want to try vim ../project-b<TAB> to try to make command completion work. However, bash refuses to complete this, because it thinks that .. is the directory containing user homes.

However, if I type in vim ../project-b-2.2/somefile.txt then that works fine, which is what I expected.

Symlinks are not directories, and all kinds of inconveniences and even errors happen because of this mis-feature in bash. I've tried to search for an option to turn this off, but all the google and superuser hits are just about "how to I manually resolve a link path" -- that's not what I want here; I want bash to stop trying to emulate a file system on top of my file system, poorly. Surely, there exists some option that will put correctness in front of illusion?

The "similar questions" popup pointed at two other questions that Google already sent me to; both of them require me to pass the "-P" option to pwd or cd or even recommend using readlink to figure out the symbolic link target. That's not at all what I'm interested in. I want the built-in pwd and the shell prompt $PWD to match the physical output of the getcwd() system call; those questions don't talk about that at all.


There is a shell-wide option for this:


If set, do not resolve symbolic links when performing commands such as cd which change the current directory. The physical directory is used instead. By default, Bash follows the logical chain of directories when performing commands which change the current directory.

For example, if /usr/sys is a symbolic link to /usr/local/sys then:

$ cd /usr/sys; echo $PWD
$ cd ..; pwd

If set -P is on, then:

$ cd /usr/sys; echo $PWD
$ cd ..; pwd

So this should get you the behaviour you want:

set -P
| improve this answer | |
  • Thank you; that was a great answer to the exact problem I'm trying to solve. Hopefully this question will show up on Google for whoever comes next and has this same problem! – Jon Watte Apr 24 '18 at 16:09

This may not be what you want to hear, but I would argue that the idea of a canonical path to a file is flawed.

First, if you create a hard link to an existing file there are now literally two distinct paths to the same file:

$ cd "$(mktemp --directory)"
$ touch foo
$ ln foo bar
$ ls --inode 
1223418 bar  1223418 foo

There is no "original" among these two, and they keep the same metadata except for their name:

$ touch --date='2001-02-03 04:05:06.789' bar
$ ls -lA
total 0
[…] Feb  3  2001 bar
[…] Feb  3  2001 foo

Second, there are many ways to refer to a file, depending on context:

  • Relative paths to a hard or symbolic link
  • Absolute paths (multiple, as seen above) to a hard or symbolic link
  • file:///absolute/path/to/file or other protocols

All of these are useful in different contexts.

Third, Bash isn't "pretending" anything; there is no illusion, you really are in that directory. The fact that it is a symlink should be transparent to almost all actions you would ever do with it.

Fourth, symlinks have nothing to do with Bash; they are a filesystem feature, not related to any shell, terminal or even OS. And every major filesystem has them, so trying to ignore them is probably going to hinder rather than help you.

Finally, any tool which treats symlinks specially without being explicitly told to do so should be fixed, because it has a bug.

| improve this answer | |
  • 1
    Re: Third: Bash is pretending. The result of the getcwd() function wouldn't include any symbolic links in it, so bash has to keep track of the path with symlinks in it separately. If it were actually taking the output of getcwd() and then going to its parent, you would get the behaviour OP is asking for. – muru Apr 23 '18 at 5:54
  • That isn't pretending, that's just how one specific function works. pwd prints the symlinked directory and $PWD contains the symlinked directory. – l0b0 Apr 23 '18 at 7:07
  • of course they do, they're all implemented by bash and so the same internal state is available to them. Try the external pwd command. – muru Apr 23 '18 at 7:27
  • Thank you for the answer. It turns out, I am quite aware of how the UNIX file system works. That's why I don't like how bash is pretending. And, yes, it's pretending! When "ls .." doesn't show the same thing as "cd ..; ls" then the shell has stopped helping and is hurting. I downvote your answer because I fundamentally disagree with your statements; I think they are factually wrong. – Jon Watte Apr 24 '18 at 16:09

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