A good[ish] website
Web development blog, loads of UI and JavaScript topics
This is a post about understanding linking, symbolic links and hard links.
Symlink, symbolic link, or soft link:
In computing, a symbolic link (also symlink or soft link) is a special type of file that contains a reference to another file or directory in the form of an absolute or relative path and that affects pathname resolution. —Wikipedia
Hard link:
In computing, a hard link is a directory entry that associates a name with a file on a file system. —Wikipedia
Symlink is kind of like having a directory, or a file, in two places at the same time.
If you execute a file in a path ./file-a
it actually runs the in location ./file-b
.
Hard link syntax:
┌──The link command
│
│ ┌──Path to the intended link, can use . or ~
│ │
│ ┌─────┴──────┐
ln /path/to/original /path/to/link
└───────┬───────┘
└──Path to the original file/folder can
use . or ~ or other relative paths
Symlink:
┌──The link command
│ ┌──Create a symbolic link
│ │ ┌── Path to the intended symlink, can use . or ~
│ │ │
│ │ ┌─────┴────────┐
ln -s /path/to/original /path/to/symlink
└───────┬───────┘
└── the path to the original file/folder
can use . or ~ or other relative paths
Like the name suggest, soft link is more "fragile" than a hard link.
Here’s stuff one can do with hard links that would break a soft link:
Stuff that soft links do that hard links can’t:
Maybe there’s more that I just don’t know, drop a comment if you have something to add.
There are these things called inodes (Index Nodes) inside your computer, which represent files and directories.
An inode is a data structure on a traditional Unix-style file system such as UFS or ext3. An inode stores basic information about a regular file, directory, or other file system object.
A file is really a link to an inode, hard link creates another file with a link to the same inode.
If you want to test this in practice, you can quickly make some test files with dummy content:
$ mkdir link-test \
&& cd link-test \
&& echo Banana > File_A \
&& echo Apple > File_B \
&& echo Orange > File_C \
&& mkdir Dir_A \
&& mv File_C Dir_A/File_C
That gives you:
├── Dir_A
│ └── File_C
├── File_A
└── File_B
You may see the inode number of File_A
:
$ ls -i File_A
51882811 File_A
The stat
command shows all the attributes stored into the inode:
$ stat -x File_A
File: "File_A"
Size: 7 FileType: Regular File
Mode: (0644/-rw-r--r--) Uid: ( 501/ bob) Gid: ( 20/ staff)
Device: 1,4 Inode: 51882811 Links: 1Access: Tue Jan 20 09:14:04 2015
Modify: Tue Jan 20 09:14:04 2015
Change: Tue Jan 20 09:14:04 2015
This is on OS X, the output of stat
might look a bit different on other systems.
👉 Related: Better stat command.
Files can be deleted based on their inode number:
$ find . -inum 51882811 -exec rm -i {} ;
In hard links the link sits, kind of, between the inode and the file:
$ ln File_A File_B
┌──────────┐ ┌──────────┐
│ File_A | | File_B |
└─────┬────┘ └─────┬────┘
| |
└─────┐ ┌─link──┘
| |
┌─────┴──┴─────┐
| inode |
| representing |
| File_A |
└──────────────┘
Where as soft link has nothing to do with the inode, it links between the files like so:
$ ln -s File_A File_B
┌──────────┐ ┌──────────┐
| File_A ├───link───| File_B |
└─────┬────┘ └──────────┘
|
└─────┐
|
┌─────┴────────┐
| inode |
| representing |
| File_A |
└──────────────┘
Hope I got that right, please correct me in the comments if you have a better explanation.
If link target file name is not specified, the originals name will be used:
$ cd link-test
$ ln -s /path/to/File_B .
That just grabs the File_B
from an absolute path and jugs the link into the current directory.
Any sort of a relative path can be used with links if needed:
$ ln -s ../../File_B .
The test directory has one soft link and one hard link. The -l
flag on the ls
command shows the symlink locations:
$ ls -l
-rw-r--r-- 1 bob staff 7 20 Jan 09:14 File_A
lrwxr-xr-x 1 bob staff 6 21 Jan 10:32 File_A_link -> File_A-rw-r--r-- 2 bob staff 6 20 Jan 09:14 File_B
-rw-r--r-- 2 bob staff 6 20 Jan 09:14 File_B_link
Or the more explicit command readlink
can be used:
$ readlink File_A_link
File_A
Hard links aren’t shown the same way, per se. But notice the number 2
before the user name on the ls
command output (line highlighted):
$ ls -l
-rw-r--r-- 1 bob staff 7 20 Jan 09:14 File_A
lrwxr-xr-x 1 bob staff 6 21 Jan 10:32 File_A_link -> File_A
-rw-r--r-- 2 bob staff 6 20 Jan 09:14 File_B-rw-r--r-- 2 bob staff 6 20 Jan 09:14 File_B_link ^
That means the file has two names, the original and the link. The duplicate files can be viewed with find
:
$ find . -xdev -samefile File_B
./File_B
./File_B_link
Here’s the breakdown of the command:
.
-xdev
-samefile filename
-L
is specified, it is also true if the file is a symbolic link and points to a name.File_B
$ rm File_B
$ ls
File_A File_A_link File_B_link
The File_B_link
persists, essentially it’s now the original File_B
.
Either, remove the link:
$ rm File_A_link
Or use unlink
:
$ unlink File_A_link
There is a small gotcha here, link the directory and try to remove it, and bash will nag you about it:
$ ln -s Dir_A Dir_A_link
$ unlink Dir_A_link/
unlink: Dir_A_link/: is a directory
The gotcha being the forward slash after the directory name, leave out and it should work:
$ unlink Dir_A_link
Now the File_A_link
links to File_A
:
$ ls -l File_A_link
lrwxr-xr-x 1 bob staff 6 21 Jan 15:09 File_A_link -> File_A
Update the link to point to Dir_A/File_C
:
$ ln -nsf Dir_A/File_C File_A_link
Symlink can be tested with an if
statement. The syntax is:
[ -h FILE ]
True if FILE exists and is a symbolic link.
Simple example script:
is_link() {
local file=$1
[[ -h $file ]]
}
if is_link path/to/file; then
# Do something...
fi
That’s the basics of links, thanks for reading. Please leave a comment if you have something to add.
Comments would go here, but the commenting system isn’t ready yet, sorry.