0

This sort of situation often occurs under the /sys/bus tree (bash-5.1) :

Let's say I get some foo directory listing several symlinks to other directories, ls -ails pathto_foo displaying something of the kind :

lrwxrwxrwx 1 root root    0 21 foo1 -> whatever relative path to symlinked foo1
lrwxrwxrwx 1 root root    0 21 foo2 -> whatever relative path to symlinked foo2

Each one of these symlinked dirs containing a regular file named bar :
If I change my present working directory to pathto_foo/foo1 or pathto_foo/foo2, I can file, stat, catbar without trouble.

However, my pwd being set to pathto-foo/foo1 (or pathto_foo/foo2), sat-ing/c-ating/file-ing ../foo2/bar (../foo1/bar respectively) will systematically return :

../foox/bar : No such file or directory

OK! I can, at some extreme limit understand and accept this utmost unwelcome behaviour, however, I just neither understand nor accept the following inconsistency :

If, sitting in anyone of those two directories, let's take pathto_foo/foo1, I want to stat/cat/file ../foo1/bar (yes! I do mean a relative path to the pwd) I'll be successful.

So why does the path resolution depend on the pwd ? (why are relative paths to the pwd resolved differently to other similarily written relative paths ?)
How can I prevent that and get an identical answer (successful or unsuccessful) irrespective of the pwd ?

MC68020
  • 7,981
  • Related: https://unix.stackexchange.com/questions/6800/pwd-without-symlinks – JRFerguson Dec 21 '22 at 21:55
  • @JRFerguson : Fair enough! I still fail to understand the difference in the path resolution. Why is the path resolution identical when cd-ing to ../foo1 and ../foo2 and why is the path resolution different when stat-ing ../foo1/bar and ../foo2/bar. I would have expected consistency at least from a syntactical standpoint. – MC68020 Dec 21 '22 at 22:22

1 Answers1

2

A directory can have multiple symlinks pointing to it, but it has only one real parent directory, which has nothing to do with the symlinks.

So your /sys/bus/pathto_foo contains two symbolic links:

lrwxrwxrwx 1 root root    0 21 foo1 -> /sys/some/where/foo1
lrwxrwxrwx 1 root root    0 21 foo2 -> /sys/else/where/foo2

When you are cd'd at pathto_foo:

  • your cat foo1/bar maps to cat /sys/some/where/foo1/bar
  • your cat foo2/bar maps to cat /sys/else/where/foo2/bar

When you then do a cd foo1, your real working directory will not be /sys/bus/pathto_foo/foo1 but actually /sys/some/where/foo1, although the shell (and only the shell) will remember that you referred to it as /sys/bus/pathto_foo/foo1.

Now if you do a cat ../foo1/bar, .. refers to /sys/some/where/, and since both the symbolic link and the actual directory it points to were conveniently named foo1, the full path will be /sys/some/where/foo1/bar, as expected.

If you try cat ../foo2/bar, it now maps to /sys/some/where/foo2/bar, but there is no foo2 subdirectory in /sys/some/where.

The actual foo2 was at /sys/else/where/foo2 which is in a different branch of the directory tree altogether.

And the symbolic links you used to arrive here were in /sys/bus/pathto_foo, which is not the actual .. of /sys/some/where/foo1.

When you do a cd .., the default for modern bash and most POSIX-compatible shells is do a logical shift to parent directory, i.e. cut off the right-most element of the path the user used to arrive at the current directory, and then change to that path.

Most other programs will understand the concept of "parent directory" simply as "the .. directory entry provided by the filesystem", which refers to the directory's physical parent.

The cd command of bash actually has two options, -L and -P, to explicitly request either logical or physical interpretation of the path to switch to. If you don't specify either option, the built-in default is to behave as if -L was specified, and so do as described above. If the -P option is used, the cd command will behave just like all other programs and will change to the physical parent directory whenever .. is used.

If you don't like this (mis)feature of the shell, there is probably a shell-specific way to disable it. With the bash shell, adding set -P or set -o physical to your ~/.bashrc or similar shell start-up script would make bash behave like all cd commands had the -P option unless the -L option is explicitly used.

telcoM
  • 96,466