Winter 2019 - January to April 2019 - Updated 2022-09-19 05:54 EDT
man 7 symlink
In contrast to “hard links”, symbolic links are called “soft links” or “symlinks”. They were invented to solve the limitation of not being able to make hard links to directories. Symbolic links can link to anything, even directories, so they can give multiple names to directories.
Symbolic links were brought to Unix at Berkeley (BSD Unix) in the 1980s. They are now available in Microsoft NTFS as of Windows Vista, 30 years later. See: http://www.howtogeek.com/howto/windows-vista/using-symlinks-in-windows-vista/
Symlinks are similar to Windows/Macintosh aliases and have some of
the same limitations. They are secondary names, because they don’t
change the link count field of the things they link to and they can stop
working if you rename or delete the actual file system object that is
the target of the link. Symlinks are second-class file system objects
and many programs – especially programs that recursively walk directory
trees such as find
, tree
, cp -r
, and ls -R
– don’t follow them,
so they don’t cause infinite loops in the file system.
You create a symbolic link using the -s
option to the link command
ln
, and symbolic links are identified by leading l
characters in
the output of ls -l
:
Symlink Syntax (RTFM): ln -s TARGET LINK_NAME
$ date >foo
$ ln foo hard # hard link
$ ln -s foo soft # symbolic or soft link
$ ls -li foo hard soft
1442426 -rw-rw-r-- 2 idallen idallen 29 Mar 5 06:50 foo
1442426 -rw-rw-r-- 2 idallen idallen 29 Mar 5 06:50 hard
1442454 lrwxrwxrwx 1 idallen idallen 3 Mar 5 06:50 soft -> foo
$ wc foo hard soft
1 6 29 foo
1 6 29 hard
1 6 29 soft
You will note an immediate difference between a symlink and a hard link is that a symlink is not simply another name for the same inode. A symlink gets its own inode that is used to store the link target name, which means it gets its own file type, permissions, owner, group, and modify time. A symbolic link is like a file pointing to another pathname. Creating the symlink doesn’t affect the link count of the link target.
The owner, group, and permissions of the symlink inode itself are
ignored and don’t matter. The only thing that matters in a symlink is
the target name. (The root
user can change the owner and group of
a symlink on some systems, but nothing can change the permissions of
a symlink. Read the man
pages for the chmod
and chown
commands
to see how they dereference symlinks.)
You can create and remove symbolic links without affecting the file system object that is the target of the link. Indeed, the target pathnames know nothing about symbolic links and are completely unaffected by them. Their link counts do not change. Only hard links change link counts.
Creating symbolic links with ln -s
: The first pathname
argument is the TARGET of the symlink; it is not relative to or
affected by your current directory; it’s just a piece of text.
Any one of the ln
commands below would create exactly the same symlink
bar -> foo
in the d
directory:
$ mkdir -p a/b/c/d ; date >a/b/c/d/foo
$ ln -s foo a/b/c/d/bar
$ cd a ; ln -s foo b/c/d/bar
$ cd a/b ; ln -s foo c/d/bar
$ cd a/b/c ; ln -s foo d/bar
$ cd a/b/c/d ; ln -s foo bar
The first pathname argument is the TARGET of the symlink; it doesn’t change when you change directories. The second pathname argument is where you want to create the symlink, and of course if it is a relative pathname then it changes depending on your current directory.
The process of following a symbolic link reference to its actual
file system target is called “dereferencing” the symbolic link.
Some commands automatically dereference symlinks; many do not, especially
commands that recursively walk file systems (e.g. find
, cp -r
,
tree
, etc.).
Some commands dereference symlinks when they are given on the command
line as arguments, but do not dereference them when they are encountered
in a recursive walk of the file system (e.g. chmod
, chown
, etc.).
If the target contained in the symlink is an absolute pathname (i.e. starts with a slash), then dereferencing the symlink means going to that absolute pathname.
Example 1: Dereferencing an absolute path symlink:
$ cd /tmp
$ ln -s /etc/passwd soft # the target is an absolute pathname
$ ls -l soft
lrwxrwxrwx 1 idallen idallen 11 2012-03-18 18:41 soft -> /etc/passwd
Above, the symbolic link pathname soft
is a symbolic link to the target
/etc/passwd
that is itself an absolute pathname. Referring to soft
is the same as referring to /etc/passwd
(for commands that follow
symlinks):
$ cd /tmp
$ ln -s /etc/passwd soft # the target is an absolute pathname
$ ls -l soft
lrwxrwxrwx 1 idallen idallen 11 2012-03-18 18:41 soft -> /etc/passwd
$ wc soft # same as wc /etc/passwd
$ wc /tmp/soft # same as wc /etc/passwd
$ wc ../tmp/soft # same as wc /etc/passwd
$ wc ../../tmp/soft # same as wc /etc/passwd
Example 2: Dereferencing an absolute path symlink:
$ cd
$ ln -s ~idallen/public_html/teaching/cst8207/16f/notes newnotes
$ ls -l newnotes
lrwxrwxrwx 1 idallen idallen 52 Mar 5 06:00 newnotes -> /home/idallen/public_html/teaching/cst8207/16f/notes
Above, the symbolic link pathname newnotes
in
my home directory is a symbolic link to the target
~idallen/public_html/teaching/cst8207/16f/notes
that is
itself an absolute pathname (because the shell replaces
~idallen
with /home/idallen
when it reads the leading
tilde). Referring to newnotes
is the same as referring to
/home/idallen/public_html/teaching/cst8207/16f/notes
(for commands
that follow symlinks):
$ cd
$ ln -s ~idallen/public_html/teaching/cst8207/16f/notes newnotes
$ ls -l newnotes
lrwxrwxrwx 1 idallen idallen 52 Mar 5 06:00 newnotes -> /home/idallen/public_html/teaching/cst8207/16f/notes
$ ls newnotes # same as next command:
$ ls /home/idallen/public_html/teaching/cst8207/16f/notes
$ less newnotes/week01notes.txt # same as next command:
$ less /home/idallen/public_html/teaching/cst8207/16f/notes/week01notes.txt
Example 3: Dereferencing chains of absolute path symlinks:
$ which vi
/usr/bin/vi
$ ls -l /usr/bin/vi
lrwxrwxrwx 1 root root 20 Sep 7 2012 /usr/bin/vi -> /etc/alternatives/vi
$ ls -l /etc/alternatives/vi
lrwxrwxrwx 1 root root 16 Jan 29 2013 /etc/alternatives/vi -> /usr/bin/vim.gtk
$ ls -l /usr/bin/vim.gtk
-rwxr-xr-x 1 root root 2387776 May 4 2012 /usr/bin/vim.gtk
$ file /usr/bin/vim.gtk
/usr/bin/vim.gtk: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x9044e1c3d931c29425be2a76488fa95196ee069e, stripped
Above, the pathname /usr/bin/vi
is a symlink containing absolute path
/etc/alternatives/vi
, which is itself a symlink containing absolute path
/usr/bin/vim.gtk
, which is an executable program.
$ which pico
/usr/bin/pico
$ ls -l /usr/bin/pico
lrwxrwxrwx 1 root root 22 Sep 7 2012 /usr/bin/pico -> /etc/alternatives/pico
$ ls -l /etc/alternatives/pico
lrwxrwxrwx 1 root root 9 Sep 7 2012 /etc/alternatives/pico -> /bin/nano
$ ls -l /bin/nano
-rwxr-xr-x 1 root root 191960 Dec 3 2010 /bin/nano
$ file /bin/nano
/bin/nano: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, BuildID[sha1]=0x9611a8270fb6d94668dce9de67be6a633325b558, stripped
$ which nano
/usr/bin/nano
$ ls -l /usr/bin/nano
lrwxrwxrwx 1 root root 9 Sep 7 2012 /usr/bin/nano -> /bin/nano
Above, we see that the command pico
is, through a chain of symbolic
links, actually the same program file as the command nano
.
Putting an absolute path into a symlink means that accessing the symlink accesses whatever is at the absolute path instead (for commands that follow symlinks).
If the target contained in the symlink is a relative pathname (i.e. the target in the symlink does not start with a slash), then dereferencing the symlink is done relative to the directory containing the symlink. The actual file system object referenced by the symlink is found relative to the directory containing the symlink. To find the actual object referenced by a relative symlink, use the directory name containing the symlink and append the symlink target (the relative path) onto it, e.g.:
$ ln -s bar /tmp/foo # "bar" is a relative target (no leading slash)
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 3 Mar 5 05:57 /tmp/foo -> bar
$ cat /tmp/foo # same as cat /tmp/bar
Above, any reference to to the symlink /tmp/foo
finds that the symlink
foo
contains the relative (not absolute) path bar
, so the resulting
pathname for /tmp/foo
is taken to be the directory containing the
symlink (/tmp
) with the relative path bar
appended, giving /tmp/bar
:
$ ln -s bar /tmp/foo # "bar" is a relative target (no leading slash)
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 3 Mar 5 05:57 /tmp/foo -> bar
$ cat /tmp/foo # same as cat /tmp/bar
$ cat ../tmp/foo # same as cat ../tmp/bar
$ cat ../../tmp/foo # same as cat ../../tmp/bar
The directory containing the symlink may be the current directory:
$ ln -s bar /tmp/foo # "bar" is a relative target (no leading slash)
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 3 Mar 5 05:57 /tmp/foo -> bar
$ cd /tmp
$ cat foo # same as cat bar because foo -> bar
In the cat foo
line above, foo
is a relative pathname,
and relative pathnames are always relative to the current directory.
The current directory is /tmp
, so cat foo
(a relative path)
is the same as cat /tmp/foo
(the absolute path). Since the
foo
in /tmp/foo
is itself a symbolic link with a relative target
bar
inside it, the rule is to take the containing directory /tmp
and append the relative target bar
to it, giving /tmp/bar
. So
cat foo
is the same as cat bar
.
Another example using the relative target ..
:
$ ln -s .. /tmp/foo # ".." is a relative target (no leading slash)
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 2 Mar 5 06:00 /tmp/foo -> ..
$ ls /tmp/foo # same as ls /tmp/..
$ cd /tmp
$ ls foo # same as ls .. because foo -> ..
Another example using the relative target .
:
$ ln -s . /tmp/foo # "." is relative target (no leading slash)
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 1 Mar 5 06:00 /tmp/foo -> .
$ ls /tmp/foo # same as ls /tmp/.
$ cd /tmp
$ ls foo # same as ls . because foo -> .
Another example using the relative target a/b
:
$ ln -s a/b /tmp/foo # "a/b" is a relative target (no leading slash)
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 3 Mar 5 06:00 /tmp/foo -> a/b
$ ls /tmp/foo # same as ls /tmp/a/b
$ cd /tmp
$ ls foo # same as ls a/b because foo -> a/b
More examples showing how rbash
and sh
are synonyms for bash
and
dash
:
$ ls -l /bin/*sh
-rwxr-xr-x 1 root root 959120 Mar 28 2013 /bin/bash
-rwxr-xr-x 1 root root 109768 Mar 29 2012 /bin/dash
lrwxrwxrwx 1 root root 4 Mar 28 2013 /bin/rbash -> bash
lrwxrwxrwx 1 root root 4 Sep 7 2012 /bin/sh -> dash
lrwxrwxrwx 1 root root 7 Nov 16 2012 /bin/static-sh -> busybox
Above, pathname /bin/rbash
is a symlink with relative target bash
,
so to dereference the relative symlink /tmp/rbash
we take the directory
containing the symlink (/bin
) and we append the relative target path
bash
giving /bin/bash
. So /bin/rbash
is really /bin/bash
.
Above, pathname /bin/sh
is a symlink with relative target dash
,
so to dereference the relative symlink /bin/sh
we take the directory
containing the symlink (/bin
) and we append the relative target path
dash
giving /bin/dash
. So /bin/sh
is really /bin/dash
.
.
(dot) as a Symlink TargetIndexA symlink containing .
refers to the directory it is in, and can make
a directory name “disappear” in a pathname:
$ ln -s . /usr/local # "." is relative to "/usr/" so "/usr/."
$ ls -l /usr/local/bin # same as /usr/./bin or /usr/bin
If you have a program that insists on using /usr/local/bin
but you want
it to use simply /usr/bin
, you can make the local
disappear in your
file system by making /usr/local
a symlink to .
in your system.
You can put any text you like into the target of a symbolic link. The target doesn’t have to exist or even look like a file name. If the target doesn’t resolve to an existing file system object, the program accessing the symlink will give an appropriate error:
$ ln -s nosuchfile bar
$ ls -l bar
lrwxrwxrwx 1 idallen idallen 10 Feb 9 10:42 bar -> nosuchfile
$ cat bar
cat: bar: No such file or directory
$ ln -s "This is some random text that fits into the symlink." foo
$ ls -l foo
lrwxrwxrwx. 1 idallen idallen 52 2012-03-18 19:25 foo -> This is some random text that fits into the symlink.
$ cat foo
cat: foo: No such file or directory
Note that the error message always uses the name of the symlink, not
the name of the symlink target. Only by later examining the pathname
would you discover that both foo
and bar
were actually symlinks to
nonexistent files. A non-functional symlink is called a “broken” or
“dangling” symlink; it’s a link to something that doesn’t exist.
The system will only process a limited number of symbolic link references when resolving a pathname. Most Unix/Linux systems give you least eight levels, and the Course Linux Server currently supports 40. If you create a symlink that links back to itself, either directly or via another symlink, you get an error that the link count has been exceeded:
$ ln -s foo foo
$ ls -l foo
lrwxrwxrwx 1 idallen idallen 3 Mar 5 07:12 foo -> foo
$ cat foo
cat: foo: Too many levels of symbolic links
$ ln -s a b
$ ln -s b a
$ ls -l a b
lrwxrwxrwx 1 idallen idallen 1 Mar 5 07:11 a -> b
lrwxrwxrwx 1 idallen idallen 1 Mar 5 07:11 b -> a
$ cat a
cat: a: Too many levels of symbolic links
$ cat b
cat: b: Too many levels of symbolic links
As mentioned above, the Course Linux Server can currently (March 2017) resolve a chain of up to 40 symbolic links.
ls
, rm
, chmod
, chown
, find
, grep
IndexMost commands that do not normally dereference (follow) symbolic links can be made to do so with appropriate command line options – see the man pages.
The ls
command treats symbolic links somewhat inconsistently, in that
saying ls -l symlink
will show the symlink itself but ls symlink
and ls -R symlink
will access the target of the symlink, and if the
target is a directory you get to see the contents of the target directory.
The rm
command does not follow symbolic links. rm -r symlink
removes only the symlink, not the target.
Both chmod
and chown
do follow symlinks given on the command line,
but ignore symlinks discovered in a recursive descent (-R).
The find
command does not follow symbolic links by default.
Using grep
with the “recursive” option does follow symlinks
(and there is no way to prevent this – be careful of file system loops!).
.
)IndexAs noted in the previous section, many commands behave differently if
they operate on symlinks or real directories. Sometimes you want the
directory behaviour, but all you have is the symbolic link name and you
don’t get what you wanted. For example, you might want to see the list
of system mailboxes under /var/mail
, but on this system /var/mail
isn’t a directory, it’s a symlink, and so you don’t get the contents of
the directory when you ls
, all you get is the symlink:
$ ls -l /var/mail
lrwxrwxrwx. 1 root root 10 2011-09-02 09:43 /var/mail -> spool/mail
The trick is to append /.
to the symbolic link name to turn it into
a real directory so that ls
shows the real contents:
$ ls -l /var/mail/.
-rw-rw----. 1 idallen mail 0 2011-09-02 10:19 idallen
-rw-rw----. 1 flanders mail 0 2012-03-11 03:48 flanders
-rw-rw----. 1 homer mail 0 2012-03-11 03:48 homer
-rw-------. 1 root root 831 2011-09-26 01:52 root
-rw-rw----. 1 rpc mail 0 2011-09-02 09:48 rpc
A basename of .
(or ..
) can never be a symbolic link; it’s always a
real directory, so if foo
is a symlink to a directory, then foo/.
is
the real directory that is the target of the symlink, and commands
ls -l foo
and ls -l foo/.
give very different results, as
do find foo
and find foo/.
:
$ ln -s / foo # foo is a symlink to the ROOT
$ ls -ld foo # using "foo" shows only the symbolic link "foo" itself
lrwxrwxrwx. 1 idallen idallen 1 2012-03-18 20:07 foo -> /
$ ls -ld foo/. # "." is inside ROOT; shows the actual ROOT directory
dr-xr-xr-x. 23 root root 4096 2012-03-11 03:49 foo/.
$ find foo # using "foo" finds only the symbolic link "foo" itself
foo
$ find foo/. # finds every file on the whole system from the ROOT down
foo/.
foo/./var
[...many many file names here...]
If you want to be sure that a directory pathname is not a symbolic link
(or you don’t know if the name might be a symbolic link now or in future),
always append /.
to the directory name to get the actual directory
instead of the link name. (Of course this does not work for file
names, since you can’t append /.
to a file.)
Mini test:
Q: How do you create a symlink named /tmp/foo that contains the path "/bin"?
A: ln -s /bin /tmp/foo
$ ls -l /tmp/foo
lrwxrwxrwx 1 idallen idallen 4 Oct 22 12:22 /tmp/foo -> /bin
Q: What does this do: ln -s foo bar ; ln -s bar foo ; cat foo
A: cat: foo: Too many levels of symbolic links
$ ls -l foo bar
lrwxrwxrwx 1 idallen idallen 3 Oct 22 12:21 bar -> foo
lrwxrwxrwx 1 idallen idallen 3 Oct 22 12:21 foo -> bar