What is a symbolic link made from? Understanding the structure of symlinks
Symlinks
Autodereferenced references to filenames
A symlink is literally a text file that's treated specially by the kernel and whose contents is a path to another file/directory.
You can read the contents of a symlink file with readlink
, and if you standardly open a symlink file, the system will open the file/directory referenced by contents of the symlink.
Pointer/C++ reference analogy
If you're familiar with C/C++, then a symlink behaves somewhat like a C++ reference or an autodereferenced pointer in most contexts (not all: e.g., rm
or mv
work directly on the symlink, not on the target). The difference is that real C++ references bind to memory addresses whereas symlinks bind to filesystem addresses.
Dangling symlinks
The contents of a symlink don't have to be a valid filepath reference --> then you have a dangling symlink (like danglig pointer or a dangling reference).
Relative symlinks
If the filepath in a symlink isn't an absolute one (starting with /
), then the relative filepath is resolved relatively to the location of the symlink (in non-symlink contexts, relative paths are resolved relatively to the $PWD
).
The -s Flag and Hardlinks
The -s
flag is for "create symlinks". ln
can also create hardlinks.
Hardlinks operate at another level, which is closer to the implementation of the filesystem (consequently, you cannot create hardlinks across different filesystems).
Unix filesystems store filenames(/directory names) and file contents (directory contents) separately, and names are just autodereferenced reference-counted pointers to their contents. A hardlink creates another name for the same contents while increasing the reference count.
$ echo 'the contents' > f1
$ ls -l f1
* 1 * #the 2nd column is the reference count
$ ln f1 f2 #create another name for the contents of f1
$ ls -l f1
* 2 * #the contents of f1 has two named references to it
$ rm f1 #the contents of f1 lives on (in f2) #
# because rm only removes the reference to the data block
#and this isn't the only reference
#(rm ivokes a system call literally named `unlink`)
Directory hardlinks
You can't create directory hardlinks, but .
and ..
are directory hardlinks implicitly created for you. Consequently the hardlink count for a directory reflects how many subdirectories it has (each subdirectory comes with a ..
hardlink to the parent).
Symlinks and Hardlinks—Big Picture Overview:
echo 'file data' > fileName
ln fileName fileName2 #hardlink
ln -s "$PWD/fileName" absoluteSymlinkTofileName
ln -s fileName relativeSymlinkTofileName
On the same physical file system, ln
creates another name for file data
(ln
will fail across filesystems). You can delete either fileName
or fileName2
and as long as at least one name remains, file data
lives on.
absoluteSymlikTofileName
is an autodereferenced reference to the fileName
name. As long as that path resolves to something, the symlink is valid. If you delete the target, the symlink dangles. This is an absolute symlink so you can move it to other places without changing its validity.
relativeSymlinkToFileName
refers to a name called fileName
in the same directory as the directory of relativeSymlinkToFileName
. If you move it to another directory that also has a file (or directory) named fileName
, then it'll point to that instead.
The
ln
command creates the symlink in the current directory if no directory is specified. Thus,phpmyadmin.conf
is put in/etc/apache2/conf-enabled/
. You could have also doneln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-enabled/phpmyadmin.conf
This is standard behavior for pretty much all Unix commands.
The
-s
option specifies that you are creating a soft link as opposed to a hard link. Read more here.I don't quite understand the question ("how can the system know where it is?").
phpmyadmin.conf
is created in the current directory (in this case/etc/apache2/conf-enabled/
).
ln -s /etc/phpmyadmin/apache.conf phpmyadmin.conf
3. This command creates a symbolic link at the location /etc/apache2/conf-enabled/phpmyadmin.conf
, whose target is /etc/phpmyadmin/apache.conf
. After this, opening the file /etc/apache2/conf-enabled/phpmyadmin.conf
is equivalent to opening /etc/phpmyadmin/apache.conf
. If /etc/phpmyadmin/apache.conf
exists, then /etc/apache2/conf-enabled/phpmyadmin.conf
has the same content. If /etc/phpmyadmin/apache.conf
doesn't exist then opening /etc/apache2/conf-enabled/phpmyadmin.conf
will fail, just as if /etc/apache2/conf-enabled/phpmyadmin.conf
didn't exist.
A symbolic link is just text. The link itself keeps existing and pointing to the same target whether that target exists or not. This allows, for instance, symbolic links to removable drives to keep existing whether the drive is present or not, or replacing a file that a symbolic link happens to point to (the fact that the target might temporarily stop existing doesn't affect the symbolic link). When the target doesn't exist, the symbolic link is said to be broken
1. The link could have been created without changing the current directory. Of course the command would have to be changed to include the full path to the desired link.
ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-enabled/phpmyadmin.conf
When the a symbolic link is absolute (i.e. its target is an absolute path), there's no advantage to changing to the directory before creating the link. When a symbolic link is relative, there is an advantage, because the first argument to ln -s
is the target of the link, and it's interpreted relative to the location of the link, not to the current directory at the time the ln
command is run. For example, a relative link could have been made like this:
ln -s ../../phpmyadmin/apache.conf /etc/apache2/conf-enabled/phpmyadmin.conf
But if the current directory isn't /etc/apache2
then in general ../../
isn't /etc
, so ../../phpmyadmin/apache.conf
isn't an existing target; for example it won't be picked up by shell completion.
2. The ln
command existed before symbolic links. It originally created hard links, which have a significantly narrower use case so aren't used much. Although ln -s
is used more often than plain ln
, the meaning of plain ln
can't be changed because that would break backward compatibility.