A link is a second name for a file — and understanding what that means is one inode's worth of knowledge that makes the whole Linux filesystem click. ln creates these names, in two flavours that behave very differently.
Two kinds of links #
$ ln notes.txt notes-hard.txt
$ ln -s notes.txt notes-soft.txt
$ ls -li notes*
1234 -rw-r--r-- 2 ana ana 512 Oct 21 notes.txt
1234 -rw-r--r-- 2 ana ana 512 Oct 21 notes-hard.txt
1237 lrwxr-xr-x 1 ana ana 9 Oct 21 notes-soft.txt -> notes.txt
The -i flag shows inode numbers. notes.txt and its hard link share inode 1234 — they are two directory entries for the same data, indistinguishable in seniority. The symlink is inode 1237, a separate small file whose content is a path.
What each one can do #
| Property | Hard link | Symlink |
|---|---|---|
| Cross filesystems | No | Yes |
| Link to a directory | No (usually) | Yes |
| Survives target deletion | Yes | No — goes dangling |
| Shows the target path | No | Yes (ls -l) |
| Size | The file's | The path's length |
The "survives deletion" row is the philosophical difference: a hard link keeps the data alive because the data's reference count is still positive; a symlink is only ever a pointer, and a dangling one at that.
Everyday use #
Symlinks do the daily work — version-switching without repaths:
$ ln -sfn releases/v1.4 current
-sfn refreshes an existing link rather than nesting inside it. Dotfiles managed from a repository are the same trick: one symlink per file into ~.
Hard links earn their keep in backups — tools like rsync's --link-dest and every snapshot system build trees of hard links so unchanged files cost zero extra space:
$ cp -al current/ snapshot-2026-10-21/
See stat, file, and which for inspecting what links point at, and df and du for why link trees keep snapshots cheap. More in the terminal notes.
