LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (http://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Symbolic links to directories mystery. (http://www.linuxquestions.org/questions/linux-newbie-8/symbolic-links-to-directories-mystery-898683/)

NoStressHQ 08-21-2011 08:26 PM

Symbolic links to directories mystery.
 
Hi,

Although I'm quite at ease with command line and shell and fs (supposedly :) ), I just encountered a weird behavior which I am able to reproduce. I can't access some symlink from another symlink. Here it is.

Code:

~$ mkdir tmp ; cd tmp

~/tmp$ mkdir -p {contoto/toto,contata/tata} ; touch contoto/toto/toto.txt ; touch contata/tata/tata.txt

~/tmp$ ln -s contoto/toto/ symtoto ; ln -s contata/tata/ symtata

~/tmp$ ls -l symtoto symtata
lrwxrwxrwx 1 me myself 13 Aug 22 03:03 symtata -> contata/tata/
lrwxrwxrwx 1 me myself 13 Aug 22 03:03 symtoto -> contoto/toto/

~/tmp$ ls -l --dereference-command-line-symlink-to-dir symtata
total 0
-rw-r--r-- 1 me myself 0 Aug 22 03:02 tata.txt

~/tmp$ cd symtoto
~/tmp/symtoto$ ls -l --dereference-command-line-symlink-to-dir ../symtata
ls: cannot access ../symtata: No such file or directory

Just a tree to graphically see what is being constructed:

Code:

~/tmp$ tree
.
|-- contata
|  `-- tata
|      `-- tata.txt
|-- contoto
|  `-- toto
|      `-- toto.txt
|-- symtata -> contata/tata/
`-- symtoto -> contoto/toto/

Could someone explain me this behavior ? That happened to me when I wanted to move the content of a subdir of a "parent symlink" from a sibling symlink (in the "real life" case, the links are even absolute references, and the bash completion is working great itself). I know that some tools need to explicitly handle symbolic links (as I do with ls), but even with that it doesn't work from the other symlink.

Sorry, I must have missed something stupid in my now long time ago education :).

Thanks !

David the H. 08-21-2011 08:56 PM

When you cd into symtoto, you are now actually in ~/tmp/contoto/toto. The directory above that is ~/tmp/contoto, which doesn't contain the symlink you want.

Try ls ../../symtata instead, or ls $OLDPWD/symtata.

The shell is applying the logical directory structure, while the external program ls is looking at the actual physical directory structure. You can use set -P (a.k.a. set -o physical) to force bash to use the physical structure instead.

man bash > set built-in
Quote:

-P If set, the shell does not follow symbolic links when executing commands such as cd that change the current working directory. It uses the physical directory structure instead. By default, bash follows the logical chain of directories when performing commands which change the current directory.


NoStressHQ 08-21-2011 09:06 PM

Oh! So you're telling me that ".." in a directory is actually a real link to the parent, and NOT a symbolic convention that work on the "path" (as a string of char). Alright, I didn't understood that. Thank you, I thought it was really an abstraction to build a "new path string" and not a real inode link.

Again, thank you for your fast answer :).

Edit: Alright, I simply did what I should have done before posting:
Code:

~/tmp$ cd symtata ; ls -l ..
and indeed it shows me the light :)

David the H. 08-21-2011 09:30 PM

That's right. . and .. are not shell synonyms, but actual directories, as defined by the posix standard for filesystems (I believe). The shell just passes these directly to the command being executed, like any other file name.

It appears that the confusion mostly comes from tab completion, which is acting according to bash's logical directory structure, before the command is executed. So there's a discrepancy between the apparent an actual directory contents. This is probably something that needs to be fixed in the tab completion scripts.

pwd/$PWD also displays the logical directory name, making it even harder to detect that you're in a symlinked directory. Running readlink -f $PWD will give you the real location.

NoStressHQ 08-21-2011 09:47 PM

Quote:

Originally Posted by David the H. (Post 4449705)
pwd/$PWD also displays the logical directory name, making it even harder to detect that you're in a symlinked directory. Running readlink -f $PWD will give you the real location.

Yes, and I also saw that simply
Code:

$ pwd -P
will do the job too:
Code:

pwd [-LP]
              Print  the absolute pathname of the current working directory.  The pathname printed contains no symbolic links if the -P option is supplied or the
              -o physical option to the set builtin command is enabled.  If the -L option is used, the pathname printed may contain symbolic links.  The  return
              status is 0 unless an error occurs while reading the name of the current directory or an invalid option is supplied.

Thanks again, I'm glad to have learn something today :).

David the H. 08-21-2011 10:29 PM

Hey, you taught me something too. I was not aware of (or forgot about) pwd -P. :)

It doesn't help with $PWD though, which I tend to use quite often in scripts. :(

NoStressHQ 08-21-2011 11:25 PM

Maybe $(pwd -P) could do the job ? (I guess you have already thought about that ;) ).

Cheers.

David the H. 08-22-2011 01:25 AM

Yeah, of course you can do that. But it requires opening up a subshell to run the command, as opposed to simply reading a variable, so it's sub-optimal. I did once use readlink in the same way for a script that could encounter symlinked files.

But I don't usually use symlinks to directories myself, so most of my scripts are unlikely to be affected by this. It is a theoretical concern, however.


All times are GMT -5. The time now is 11:18 AM.