By default on your system, ln
resolves the source fully if it is a symbolic link. There is a standard option, -P
, that prevents it from doing this:
$ mkdir dir
$ ln -s dir soft
$ ls -l
total 4
drwxr-xr-x 2 myself wheel 512 Sep 21 22:39 dir
lrwxr-xr-x 1 myself wheel 3 Sep 21 22:39 soft -> dir
$ ln -P soft hard
$ ls -il
total 4
129605 drwxr-xr-x 2 myself wheel 512 Sep 21 22:39 dir
129606 lrwxr-xr-x 2 myself wheel 3 Sep 21 22:39 hard -> dir
129606 lrwxr-xr-x 2 myself wheel 3 Sep 21 22:39 soft -> dir
The POSIX specification for the ln
utility says:
If source_file is a symbolic link:
If the -P
option is in effect, actions shall be performed equivalent to the linkat()
function with source_file
as the path1
argument, the destination path as the path2
argument, AT_FDCWD
as the fd1
and fd2
arguments, and zero as the flag
argument.
This text is mostly gibberish unless you know what linkat()
is. The OpenBSD manual translates this into
-P
When creating a hard link and the source is a symbolic link, link
to the symbolic link itself. The -P
option overrides any
previous -L
options.
... and the GNU manual says
-P
--physical
If -s
is not in effect, and the source file is a symbolic link, create the hard link to the symbolic link itself. On platforms where this is not supported by the kernel, this option creates a symbolic link with identical contents; since symbolic link contents cannot be edited, any file name resolution performed through either link will be the same as if a hard link had been created.
Interestingly, GNU ln
on (Ubuntu) Linux has this in the manual:
Using -s
ignores -L
and -P
. Otherwise, the last option specified controls behavior when a TARGET
is a symbolic link, defaulting to -P
.
Whereas on OpenBSD and macOS (and presumably on other systems as well), the same GNU ln
manual says
Using -s
ignores -L
and -P
. Otherwise, the last option specified controls
behavior when a TARGET
is a symbolic link, defaulting to -L
.
(Another reason to always read the manual on the system you're using rather than on some random page on the internet, which seems to happen far too often.)
ln
on a BSD system would produce. GNUln
also does this on BSD systems (gln: soft: hard link not allowed for directory
).