0

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. (Of course with the symlinks expanded, /tmp/sb/sa is /tmp/a/b/.., i.e. /tmp/a.) 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? Commented Jan 1, 2023 at 20:29
  • @Shynur, pretty much yeah. Commented Jan 1, 2023 at 20:37

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.