Two Ways to Point
Sometimes you want a file to appear in two places at once without duplicating the data. Linux provides two mechanisms for this: hard links and soft links (also called symbolic links or symlinks). They look similar on the surface but work in fundamentally different ways.
Hard Links: Multiple Names, One File
A hard link is simply another directory entry pointing to the same inode. Remember, a directory entry is just a name-to-inode mapping. Creating a hard link adds a second name-to-inode mapping for the same inode number — a second name for the exact same file. Listing both names afterward shows them sharing the identical inode number, with the link count now at 2. There is no "original" and no "copy" — both names are completely equal peers.
Hard link characteristics:
- Indistinguishable from the "original" — there is no original, just two equal names for one inode
- Must exist on the same filesystem/partition (inode numbers are filesystem-local)
- Cannot link to directories (the kernel forbids this to prevent circular loops that would break tools like find and du)
- If you delete one name, the data persists because the other name still references the inode
- The inode (and data blocks) is only freed when the link count drops to zero
Real-world use case: Backup systems like rsync --link-dest use hard links to create space-efficient incremental backups. If a file hasn't changed between Monday's and Tuesday's backup, Tuesday's backup directory contains a hard link to Monday's copy rather than a duplicate. You get the appearance of a full backup every day while only storing changed data.
Soft Links (Symbolic Links): Shortcuts
A soft link is a special file whose content is simply the path string to another file. It's conceptually identical to a Windows shortcut or macOS alias. When you access a symlink, the kernel reads the path string inside it and transparently redirects you to the target. A soft link gets its own, different inode number; listing it shows an l file type and a -> arrow indicating what it points to, e.g. softlink.txt -> original.txt. Its reported size is simply the length of the target path string it stores, not the size of the target's actual data.
Soft link characteristics:
- Has its own inode (it's a real file, just a special type containing a path string)
- Can point to files on different filesystems or partitions
- Can link to directories (this is how /usr/bin → /bin consolidation works)
- Can use relative or absolute paths (relative paths are resolved from the symlink's location, not your current directory)
- If the target is deleted, the soft link becomes "broken" or "dangling" — it still exists but resolves to nothing
- Permissions shown on the symlink itself (lrwxrwxrwx) are meaningless; the target's permissions apply
Real-world use cases:
- /usr/bin/python → /usr/bin/python3.11 (version management without breaking scripts)
- /etc/alternatives/ system for managing multiple installed versions of a program
- Deployment patterns: /var/www/current → /var/www/releases/v2.4.1/ — switching the live version is a single atomic symlink swap
Quick Comparison
| Feature | Hard Link | Soft Link |
|---|---|---|
| Same inode as target | Yes | No |
| Cross filesystem | No | Yes |
| Link to directories | No | Yes |
| Survives target deletion | Yes | No (becomes broken) |
| Created with | ln target link |
ln -s target link |
| Identify with | ls -li (same inode) |
ls -l (shows ->) |
Key Point: When you see a path like /usr/bin/python, always check if it's a symlink with ls -l /usr/bin/python or readlink -f /usr/bin/python. The latter resolves the entire chain and shows the final real file. Understanding symlink chains is essential for debugging "command not found" errors, version mismatches, and deployment issues where the "current" symlink points to the wrong release.