0

I would like to remove a symlink and link it to something different, and I think there are 3 ways to do this:

ln -sfn source dest
rm dest
ln -s source dest
unlink dest
ln -s source dest

Are all 3 of these equivalent? Should one be preferred over another?

2 Answers2

4

They are not equivalent.

In:

ln -sfn source dest

The -n option to not dereference the destination is a non-standard extension (I believe from GNU ln, added there in version 3.10 in 1994). Some other lns have -h for the same feature (such as NetBSD since 1997), and on some others, like Solaris/Illumos -n is for something else (predates GNU ln's -n).

Assuming the GNU behaviour of -n, if dest exists as a directory, that creates a dest/source file replacing a file by that same name if any as long as it's not itself a directory.

Otherwise, if creates a dest symlink to source replacing the existing file if any.

ln like cp or mv have that annoying ambiguous interface where they can do either move/copy/link to the destination or into the destination but that's decided based on the type of the last argument (or number of arguments) as opposed to what the user wants.

In:

rm dest
ln -s source dest

rm will attempt to remove a dest, possibly prompting the user under some conditions, and regardless of whether rm succeeded or not will run ln -s source dest which will create either dest/source (if dest is a directory which rm could not have removed or a symlink to a directory which rm may have been unable to remove for instance because you don't have write access to the current directory), or dest as a symlink to source (failing if a non-directory file exits by that name).

With:

unlink dest
ln -s source dest

Same except for the prompting part and for the fact that on some systems and under some conditions, unlink may be able to unlink a directory. unlink is also flagged under the XSI option in the POSIX specification and will not be as widely available as rm.

So if the intention is to try to create a dest symlink to source, you rather want:

  • GNU specific:

    ln -sfT source dest
    

    (where -T disables the into mode, treating dest as the intended file to create regardless of whether it's a directory or not).

  • Portable:

    rm -f dest && ln -sf source dest
    

    rm with -f does not prompt the user and does not fail if the file wasn't there in the first place. When it succeeds, you know the file is no longer there (or at least wasn't at the time rm checked after it succeeded to remove it). Beware however that ln could still create a source/dest symlink if someone else (re)created a dest directory or symlink to directory in-between those rm and ln.

3
ln -sfn source dest

At least the documentation of GNU coreutils ln is misleading. It says:

-f, --force
                     remove existing destination files

In reality, what GNU ln -f does is making a new symlink under a temporary name, and calling renameat, which simply replaces the target symlink atomically. It does not first remove the existing symlink.

In general, that's desirable, so not sure why man ln lies.

In this case, just the results

Then things don't differ.