28

Assume I have the folders ~/a/b in my home folder, and the folder b contains a symbolic link to '..' named 'symlink'. Then I perform the following actions in bash:

hm@mach:~$ cd a/b/symlink
hm@mach:~/a/b/symlink$ pwd -P
/home/hm/a
hm@mach:~/a/b/symlink$ cd ..
hm@mach:~/a/b$ pwd -P
/home/hm/a/b

pwd -P prints the current working directory, dereferencing all symbolic links. Why is the working directory /home/hm/a/b at the end, and not /home/hm?

Hermann Speiche
  • 894
  • 1
  • 9
  • 16

2 Answers2

31

According to help cd,

  Options:
      -L        force symbolic links to be followed: resolve symbolic
                links in DIR after processing instances of `..'
      -P        use the physical directory structure without following
                symbolic links: resolve symbolic links in DIR before
                processing instances of `..'

In other words, -L means using the logical structure, whereas -P uses the actually physical directory structure.

The logical structure is like this,

$ tree a
a
└── b
    └── symlink -> ..

The actual physical structure when you go to a/b/symlink is,

a

If you want to use the real .., then you must also use cd -P:

          The -P option says to use the physical directory
          structure instead of following symbolic links (see
          also the -P option to the set builtin command);
          the -L option forces symbolic links to be followed.

An example,

$ cd
$ cd a/b/symlink   # physical location is at a/
$ cd ..            # now is at a/b
$ cd symlink       # goes back to a/b/symlink
$ cd -P ..         # follow physical path (resolve all symlinks)
$ pwd -P           # -P is optional here to show effect of cd ..
/home/sarnold
$ 
Izana
  • 2,537
  • 27
  • 33
sarnold
  • 102,305
  • 22
  • 181
  • 238
  • 10
    FYI, you can use `set -o physical` or `set -P` to make this behavior permanent. – Kevin May 04 '12 at 22:39
  • 1
    .. I should mention that the implementation is probably more in line with @geekosaur's description; I wouldn't expect overwriting `OLDPWD` with your own value would actually influence `cd ..` behavior. – sarnold May 04 '12 at 22:42
  • I agree that I don't think OLDPWD actually does anything here. I tested it by "cd"ing down a symlink chain three levels deep and then doing "cd .." a few times. It worked fine. If OLDPWD was used, it wouldn't work. OLDPWD only remembers one directory, and couldn't be used to go back more than one directory. Thus, OLDPWD isn't used. – Kevin Wheeler Nov 30 '15 at 02:04
  • 1
    The reference to `OLDPWD` in your answer is irrelevant. `OLDPWD` is used by `cd -` (not by `cd ..`). – Leon Sep 06 '17 at 08:55
  • @Leon, even in the case of having traversed a symlink to a directory? – sarnold Sep 06 '17 at 17:32
  • @sarnold Yes. `cd -` is a shortcut for `cd "$OLDPWD"` (i.e. *change to the **previous** working directory*) whereas `cd ..` means *change to the **parent** directory*). *Previous* and *parent* directories are completely different things, though they may coincide in certain situations. – Leon Sep 07 '17 at 06:10
  • You can revert back to logical with `set +o physical` – bretonics Jan 10 '18 at 20:09
  • Agree. `OLDPWD` is irrelevant. It's confusing and I just tried on my machine. I think without `-P`, it just uses the **logical** directory structure. Could someone edit it? – Izana Jan 26 '20 at 05:02
5

bash keeps track of the logical current directory path, as shown in your prompt, and interprets things like cd .. according to that. This makes things a little more consistent if you only use such paths in cd (or pushd), at the cost of unexpected things happening if you then expect the same thing to happen with paths in command arguments (or inside commands; emacs and vim have their own configurable rules for symlink handling, but most commands rely on the kernel to deal with it).

geekosaur
  • 59,309
  • 11
  • 123
  • 114