Is symlink's target relative to the destination's parent directory and if so, why?

For the one that doesn't work, if we look at the ls -l result, we get the following:

[sparticvs@sparta test]$ ls -l build/
total 0
lrwxrwxrwx. 1 sparticvs sparticvs 6 Dec 17 16:08 client -> client

Now to understand what is going on here. Let's look at the command you called:

ln -s client build/client

According to the Man Page, there are two possible matches for this format

SYNOPSIS
       ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
       ln [OPTION]... TARGET... DIRECTORY     (3rd form)

It will match on the first form (since its first). Now, the "target name" or client in your case, can be (according to the complete ln manual) arbitrary strings. They don't have to resolve to anything right now, but can resolve to something in the future. What you are creating with your invocation is a "dangling symlink" and the system does not keep you from creating these.

Now your second invocation ln -s ../client build/client is what is called a "relative symlink" (as you noted in your own post). There is a second type and that is an "absolute symlink" which would be called by doing ln -s /home/user/client build/client.

This is not a bug. According to the manual it states:

When creating a relative symlink in a different location than the current directory, the resolution of the symlink will be different than the resolution of the same string from the current directory. Therefore, many users prefer to first change directories to the location where the relative symlink will be created, so that tab-completion or other file resolution will find the same target as what will be placed in the symlink.

-- from info coreutils 'ln invocation'

That said, you MUST use either the relative or absolute path to the target.


This is indeed the intended behavior. From the ln(1) man page:

Symbolic links can hold arbitrary text; if later resolved, a relative link is interpreted in relation to its parent directory.

As to the why of it, imagine if the symlink were instead interpreted relative to its source rather than its destination. When later resolving it, you would need to know what your CWD was when you created it, which is nonsensical, let alone impossible.

Moreover, this way you get a neat and compact method to create a skeleton directory structure that you can drop anywhere in the directory tree without breaking the symlinks.

To give you an example of what I mean, let's say you're working on a project and you have a whole directory structure set up for it like so:

$ ls -1 /home/you/project
thingummies/
widgets/
wizardry/

Now suppose you wanted to create a symlink to widgets/ inside wizardry/. You have two options:

$ ln -s /home/you/project/widgets /home/you/project/wizardry

or

$ ln -s ../widgets /home/you/project/wizardry

If you then try moving /home/you/project anywhere else, a symlink created with the first form will break because it's looking for /home/you/project/widgets. The second form will keep the symlink functional because it's looking for ../widgets relative to the place it's in, regardless of where that place might be in the directory tree.

Tags:

Symlink