1

The contradiction here is how symlink deal with directory ../ in 2 ways:

  • treat the current path as the result printed by pwd
  • treat the current path as absolute path

I will discuss them with an example (pretty easy to understand).


Considering the following directory hierarchy:

/tmp/
  |__a/
  |  |__b/
  |
  |__sb=./a/b/ -> /tmp/a/b/  # the name `sb' means symbol b;
                             # `sb' is generated by:
                             # [/tmp/]$ ln -s ./a/b/ sb
  1. _

    [/tmp/]$ cd sb  # `pwd' says we are now in /tmp/
                    # let's change to /tmp/a/b/
    
    [/tmp/sb/]$ cd ../  # Now we are in /tmp/a/b/
                        # But what is /tmp/a/b/'s parent dir?
    
    [/tmp/]$   # See?  We didn't come back to /tmp/a/ BUT /tmp/
    

    It means that the current parent dir is the second from the right printed by pwd.

  2. Let's add a symlink into dir /tmp/a/b/:

    /tmp/
      |__a/
      |  |__b/
      |     |__sa=../ -> /tmp/a/  # [/tmp/a/b/]$ ln -s ../ sa
      |
      |__sb=./a/b/ -> /tmp/a/b/
    

    This time, we will come back to the actual parent dir of /tmp/a/b/:

    [/tmp/]$ cd sb  # change to /tmp/a/b/
    
    [/tmp/sb/]$ cd sa  # sa=../
                       # /tmp/sb/=/tmp/a/b/
                       #   ^    or     ^
    
    [/tmp/sb/sa/]$ ls --classify
    b/                 # ???
                       # We are now in /tmp/a/ because there is a b/ here!
    

    So Why this time it chooses to refer to the absolute path to determine the parent dir?


The contradiction arises when it comes to ../, but I suspect the same thing happens when it comes to relative path.

All the above operations are tested on CentOS 7.9

1 Answer 1

1
[/tmp/sb/]$ cd ../  # Now we are in /tmp/a/b/
                    # But what is /tmp/a/b/'s parent dir?

[/tmp/]$   # See? We didn't come back to /tmp/a/ BUT /tmp/ ```

That's because the shell remembers the path you used to get there, as a convenience.

It can be helpful in that you can link some long paths to short symlinks in your home directory, and then just go cd thelink and cd .. without ever needing to think of the long path again. Or in a multiuser system, the sysadmins can do it for you, and you need not ever even know the correct path.

But if you used pwd -P or cd -P, the shell would ignore that:

[/tmp]$ mkdir -p a/b; ln -s ./a/b sb
/tmp$ cd sb
[/tmp/sb]$ pwd -P
/tmp/a/b
[/tmp/sb]$ cd -P ..
/tmp/a$

[/tmp/sb/]$ cd sa  # sa=../
                   # /tmp/sb/=/tmp/a/b/
                   #   ^    or     ^

[/tmp/sb/sa/]$ ls --classify
b/                 # ???
                   # We are now in /tmp/a/ because there is a b/ here!

Here, the ... in the symlink is resolved by the kernel, and it doesn't know anything about what the shell thinks. The shell still shows you the path you took (sb, then sa), and cd .. gets you back to /tmp/sb. Unless you use -P.

Similarly, if you run the external pwd utility instead, it'll show you the "physical" path, since it also can't know anything about which path you took.

[/tmp/sb/sa]$ pwd
/tmp/sb/sa
[/tmp/sb/sa]$ pwd -P
/tmp/a
[/tmp/sb/sa]$ /bin/pwd
/tmp/a

Incidentally, if you use cd -P to change the directory, it resolves the symlinks for the path shown by pwd and in the prompt:

[/tmp]$ cd -P sb/sa
[/tmp/a]$ 
2
  • so, all $ pwd (not $ pwd -P) does is just to ask shell the current dir remembered by shell?
    – shynur
    Jan 1 at 20:29
  • @Shynur, pretty much yeah.
    – ilkkachu
    Jan 1 at 20:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .