Creating symbolic links in Linux

Symbolic links mean shortcuts, right?

If you ever heard that explanation, it is only partially correct, and they are present on a most modern OS. There are two kinds of symbolic links when thinking in terms of files: hard and soft:

Hard LinksSoft Links
Only link to filesCan link to directories and files
Link to contents on same diskCan reference files/folders across disks or networks
Reference inode/physical locationsIf the original file is deleted, the hard link will remain (in own inodes)
Moving a file will still allow the link to workLinks don’t follow the reference file if moved

A soft link will most likely match your expectations of a shortcut and the behavior might not be very surprising, but what use is a hard link? One of the most prominent cases of when to use a hard link is when you don’t want to break a link by moving the file it points to! A soft link is clearly more flexible and can work across file systems, which is unlike hard links, but soft links won’t work if a file is moved.

Note:

Besides creating shortcuts, you can do neat tricks like renaming argv[0] when using symbolic links. The Busybox shell is an example of that, where it contains applets that are executed by a symlink that points to ./busybox. For example, ls points to the same binary as cd! All of them point to ./busybox. This is a neat way to save space and improve run-time flags without the use of flags.

Note:

Soft links are also used in the /usr/lib or /lib folders for shared librarys. In fact, symlinks are very useful for aliasing paths or getting software to work with hard-coded paths that are inside of the binaries themselves.

How to do it…

Open a terminal, and create the whoami.sh script:

whoami.sh

#!/bin/bash
VAR=$0
echo "I was ran as: $VAR"

Execute whoami.sh and observe what has happened:

$ bash whoami.sh

Next, create a soft link to whoami.sh using the ln command:

$ ln -s whoami.sh ghosts-there-be.sh

Next, run ls-la. Notice any differences?

ls -la ghosts-there-be.sh whoami.sh

On to hard links, which are created this way using ln:

$ ln ghosts-there-be.sh gentle-ghosts-there-be.sh
$ ln whoami.sh real-ghosts-there-be.sh

Next, let’s look at the difference in results when running the commands:

$ ls -la ghosts-there-be.sh whoami.sh real-ghosts-there-be.sh gentle-ghosts-there-be.sh 
lrwxrwxrwx 1 rbrash rbrash 18 Dec 12 15:07 gentle-ghosts-there-be.sh -> ghosts-there-be.sh
lrwxrwxrwx 1 rbrash rbrash 9 Dec 12 14:57 ghosts-there-be.sh -> whoami.sh
-rw-rw-r-- 2 rbrash rbrash 45 Dec 12 14:56 real-ghosts-there-be.sh
-rw-rw-r-- 2 rbrash rbrash 45 Dec 12 14:56 whoami.sh
$ mv whoami.sh nobody.sh
$ bash ghosts-there-be.sh 
bash: ghosts-there-be.sh: No such file or directory
$ bash real-ghosts-there-be.sh 
I was ran as: real-ghosts-there-be.sh
$ bash gentle-ghosts-there-be.sh 
bash: gentle-ghosts-there-be.sh: No such file or directory

How it works…

In step one, we created whoami.sh. It is similar to the whoami command, but different because we do not print the $USER variable, but rather argument 0 (arg0, as its typically known) or $0. In laymen’s terms, we are printing out the name used to execute the code or script. When we execute whoami.sh, it prints to the console:

$ bash whoami.sh 
I was ran as: whoami.sh

To create a symbolic soft link, we use ln with the -s flag (for symbolic mode). The ln command expects to be executed in this way: $ ln -s originalFileToBeLinkedTo newFileToLinkToOldFile.

As we can see in the following code, executing ghosts-there-be.sh runs the code in whoami.sh, but arg0 is ghosts-there-be.sh. Then, when the ls command is ran with the -l -a flags (-la), we can see the soft link to whoami.sh. Notice the small size of 9 bytes!

$ bash ghosts-there-be.sh 
I was ran as: ghosts-there-be.sh
$ ls -la ghosts-there-be.sh whoami.sh 
lrwxrwxrwx 1 rbrash rbrash 9 Dec 12 14:57 ghosts-there-be.sh -> whoami.sh
-rw-rw-r-- 1 rbrash rbrash 45 Dec 12 14:56 whoami.sh

Next, we create a hard link by using the ls command without the -s flag.

The hard link, real-ghosts-there-be.sh, runs the same content as ghosts-there-be.sh, but points to the actual contents of whoami.sh, even if it is moved and renamed as nobody.sh:

$ ls -la ghosts-there-be.sh whoami.sh real-ghosts-there-be.sh gentle-ghosts-there-be.sh 
lrwxrwxrwx 1 rbrash rbrash 18 Dec 12 15:07 gentle-ghosts-there-be.sh -> ghosts-there-be.sh
lrwxrwxrwx 1 rbrash rbrash 9 Dec 12 14:57 ghosts-there-be.sh -> whoami.sh
-rw-rw-r-- 2 rbrash rbrash 45 Dec 12 14:56 real-ghosts-there-be.sh
-rw-rw-r-- 2 rbrash rbrash 45 Dec 12 14:56 whoami.sh
 mv whoami.sh nobody.sh
$ bash ghosts-there-be.sh 
bash: ghosts-there-be.sh: No such file or directory
$ bash real-ghosts-there-be.sh 
I was ran as: real-ghosts-there-be.sh
$ bash gentle-ghosts-there-be.sh 
bash: gentle-ghosts-there-be.sh: No such file or directory 
$ bash gentle-ghosts-there-be.sh 
bash: gentle-ghosts-there-be.sh: No such file or directory

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

Related Articles