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 Links
Soft Links
Only link to files
Can link to directories and files
Link to contents on same disk
Can reference files/folders across disks or networks
Reference inode/physical locations
If the original file is deleted, the hard link will remain (in own inodes)
Moving a file will still allow the link to work
Links 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:
#!/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 createdwhoami.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
