How to change a symbolic link to a directory to another target?

# ln -sv /path/to/target /path/to/link
‘/path/to/link’ -> ‘/path/to/target’

Now I want to replace that target with target2:

# ln -sfv /path/to/target2 /path/to/link
‘/path/to/link/target2’ -> ‘/path/to/target2’

Whoa! What happened there? Trailing slashes have no effect whatsoever:

ln -sfv /path/to/target2/ /path/to/link
‘/path/to/link/target2’ -> ‘/path/to/target2/’

# ln -sfv /path/to/target2/ /path/to/link/
‘/path/to/link/target2’ -> ‘/path/to/target2/’

# ln -sfv /path/to/target2 /path/to/link/
‘/path/to/link/target2’ -> ‘/path/to/target2’

How to achieve ’/path/to/link’ -> ’/path/to/target2’ ?


Solution 1:

Use -n/--no-dereference ("treat LINK_NAME as a normal file if it is a symbolic link to a directory"):

$ ln -sv /var/log /tmp/my-link
‘/tmp/my-link’ -> ‘/var/log’
$ ln -sfnv /var/opt /tmp/my-link
‘/tmp/my-link’ -> ‘/var/opt’

That is, ln -s target link will work like ln -s target link/target if link links to a directory.

Most Linux command tools will try to dereference symbolic links before applying their action, otherwise symbolic links would be mostly just confusing and almost useless. I guess the original ln authors thought consistency was more important than a certain amount of simplicity (with the risk of being confusing to people used to other tools) in this case.

Solution 2:

l0b0's answer is a good one. It's simple, and that makes it the best for command line use most of the time. In some cases though, you might care that it's not atomic. ln -sf first deletes the old symlink, then creates the new one, so there's a brief period where no symlink exists.

If there's a need to be careful, you are better off to create the new symlink in a temporary location, and then mv it into place.

There's a ruby implementation of that here: http://blog.moertel.com/posts/2005-08-22-how-to-change-symlinks-atomically.html. It'd be easy to implement in any language though. Beats me why it's not the default behaviour of ln.