ln Command

Create Hard and Symbolic Links in Linux

Overview

ln creates links between files, allowing multiple filenames to reference the same data. Linux supports two types of links: hard links (multiple directory entries pointing to the same inode) and symbolic links or symlinks (special files containing paths to other files). Understanding links is fundamental to Unix filesystem concepts and essential for efficient system administration, package management, and file organization.

Hard Links vs Symbolic Links

Feature Hard Link Symbolic Link (Symlink)
Command ln source target ln -s source target
What it is Additional directory entry for same inode Special file containing path to target
Inode Same inode as original file Different inode (its own)
Cross filesystem No - must be same filesystem Yes - can link across filesystems
Link to directories No (except for system) Yes
Original deleted File remains accessible via other links Link becomes broken/dangling
Disk space No additional space (same data) Tiny (just stores path string)
Permissions Always same as original (shared inode) Own permissions (usually 777, actual access controlled by target)
Relative paths N/A Can use relative or absolute paths
Link count Increments original's link count Doesn't affect original's link count
Find original find -inum [inode] readlink -f symlink
Hard Link Concept:
┌──────────────┐
│   Inode 123  │  ← Single inode containing actual file data
│  (file data) │
└──────────────┘
      ↑     ↑
      │     │
 file1.txt  file2.txt  ← Two directory entries pointing to same inode

Symbolic Link Concept:
┌──────────────┐        ┌──────────────┐
│   Inode 123  │   ←────│   Inode 456  │
│ (file data)  │        │ (path string)│
│  file1.txt   │        │  → file1.txt │
└──────────────┘        └──────────────┘
                              ↑
                          symlink

Example 1: Create a Symbolic Link (Most Common)

$ ln -s /path/to/original /path/to/link
$ ln -s /usr/bin/python3.9 /usr/bin/python
$ ln -s ~/Documents/project ~/Desktop/project
$ ln -s /var/www/html/app /var/www/current

The -s flag creates a symbolic link (symlink). This is the most commonly used form of ln because symlinks are more flexible.

Common use cases:

  • Version management: Link "python" to "python3.9" - easy to switch versions
  • Shortcuts: Create desktop shortcuts to deeply nested directories
  • Deployment: Link "current" to specific version directory for easy rollbacks
  • Configuration: Link config files to central locations
  • Convenience: Shorter paths to frequently accessed files
Best practice: Use absolute paths when creating symlinks that will be accessed from different directories. Relative paths work but can cause confusion if the link is accessed from unexpected locations.

Example 2: Create a Hard Link

$ ln original.txt hardlink.txt
$ ln /home/user/data.db /backup/data.db
# Verify both point to same inode:
$ ls -li original.txt hardlink.txt
1234567 -rw-r--r-- 2 user user 1024 Nov 7 10:00 original.txt
1234567 -rw-r--r-- 2 user user 1024 Nov 7 10:00 hardlink.txt

Hard links create additional directory entries for the same inode. Both filenames are equal - neither is more "original" than the other.

When to use hard links:

  • Backup safety: Accidental deletion of one name doesn't lose data
  • Space efficiency: Multiple "copies" with no extra disk space
  • Atomic updates: Update one link, all others instantly reflect changes
  • Deduplication: File system deduplication often uses hard links

Link count explanation: The "2" in the ls output (second column) shows this inode has 2 links (2 directory entries pointing to it). When link count reaches 0, the file is deleted.

⚠️ Limitation: Hard links can only be created on the same filesystem. You cannot hard link a file from /home to /var if they're on different partitions or drives.

Example 3: Create Symbolic Link with Relative Path

$ cd /var/www/html
$ ln -s app-v2.1 current # Relative path
$ ls -l current
lrwxrwxrwx 1 user user 8 Nov 7 10:00 current -> app-v2.1

# To update to new version:
$ ln -sfn app-v2.2 current # Force, no-dereference

Relative symlinks store the path relative to the link's location. This is useful for:

  • Portable directory structures: Moving the entire directory tree keeps links valid
  • Version switching: Common in web deployments for blue-green deployment
  • Simplicity: Shorter stored paths in the symlink

The link "current" contains just "app-v2.1" (relative), not "/var/www/html/app-v2.1" (absolute).

Deployment pattern: Keep versioned directories (app-v2.1, app-v2.2) and a "current" symlink. Web server points to "current". To deploy: update symlink to new version, restart server. To rollback: change symlink back.

Example 4: Create Links to Directories

$ ln -s /var/log/nginx ~/nginx-logs # Symlink to directory
$ ln -s ~/Projects/work ~/Desktop/work # Desktop shortcut
$ ln -s /mnt/storage/media ~/media # Mount point shortcut
# Hard links to directories NOT allowed:
$ ln /home/user/docs /backup/docs
ln: /home/user/docs: hard link not allowed for directory

Symbolic links can point to directories, but hard links to directories are prevented (except by root for special system use) to avoid creating circular references that could crash filesystem tools.

Directory symlink use cases:

  • Desktop shortcuts to project folders
  • Shortcuts to frequently accessed log directories
  • Making mounted drives appear in convenient locations
  • Organizing filesystem without moving actual data
Path behavior: When you "cd" into a symlinked directory, your shell's $PWD reflects the symlink path, but the filesystem operations work on the real target directory.

Example 5: Force Link Creation (Overwrite Existing)

$ ln -sf /usr/bin/python3.11 /usr/bin/python # Force symlink
$ ln -f original.txt backup.txt # Force hard link
# Without -f, would get error if target exists:
$ ln -s source.txt target.txt
ln: failed to create symbolic link 'target.txt': File exists

The -f (--force) option removes existing destination files before creating the link. Essential for updating links.

Common scenarios:

⚠️ Caution: -f can overwrite files silently. Double-check your command, especially when using wildcards or in scripts. Data loss is possible if you overwrite an important file.

Example 6: Interactive Mode and Backup

$ ln -si source.txt target.txt # Interactive (prompt before overwrite)
$ ln -sb source.txt target.txt # Backup existing file
$ ln -sb --suffix=.bak source.txt target.txt # Custom backup suffix
# Result with backup:
target.txt ← New symlink
target.txt~ ← Backup of original file

Safety options to prevent accidental data loss:

Script safety: In production scripts, consider using -b instead of -f to preserve the previous version in case you need to rollback.

Example 7: Create Multiple Links at Once

$ ln -s /usr/share/doc/packages/ /usr/share/doc/man/ ~/docs/
# All targets must exist, creates links in ~/docs/

# Or create links with same name in target directory:
$ cd /usr/bin
$ ln -s /opt/python3.11/bin/* .

# Create multiple links to same source:
$ ln file.txt link1.txt link2.txt link3.txt

When multiple source paths are provided, ln creates links in the target directory (last argument) with the same basenames as the sources.

For hard links with multiple targets, all names except the last must exist; the last is created as the new link.

Example 8: Verbose Output and No-Dereference

$ ln -sv /etc/nginx/nginx.conf ~/nginx.conf
'~/nginx.conf' -> '/etc/nginx/nginx.conf'

$ ln -sfn app-v3 current # Force, no-dereference

# Understanding -n (no-dereference):
# Without -n: if 'current' is a symlink, ln follows it and replaces target
# With -n: ln treats 'current' as a symlink itself and replaces it

-v (verbose): Prints what ln is doing, helpful for debugging and confirming operations.

-n (no-dereference): Treats destination that is a symlink as a normal file. Critical when updating symlinks:

Best practice for updating symlinks: Always use "ln -sfn" when updating an existing symlink to ensure you replace the link itself, not its target.

Example 9: Find All Hard Links to a File

# Get inode number:
$ ls -i file.txt
1234567 file.txt

# Find all files with same inode:
$ find /home -inum 1234567
/home/user/file.txt
/home/user/backup/file.txt
/home/user/archive/file.txt

# Or use stat to see link count:
$ stat file.txt | grep Links
Links: 3

This technique identifies all hard links to a file by searching for files with the same inode number.

Use cases:

Example 10: Manage and Check Symbolic Links

# Check if path is a symlink:
$ test -L /usr/bin/python && echo "Is a symlink"

# Read symlink target:
$ readlink /usr/bin/python
python3.9

# Get absolute path of symlink target:
$ readlink -f /usr/bin/python
/usr/bin/python3.9

# Find broken symlinks:
$ find /usr/bin -type l ! -exec test -e {} \; -print

# Find all symlinks in directory:
$ find /etc -type l -ls

Essential commands for managing symbolic links:

Maintenance script: Regularly search for broken symlinks, especially after software updates or file reorganization. Broken links can cause subtle failures in applications and scripts.

Understanding Inodes and Link Counts

What is an Inode?

An inode (index node) is a data structure that stores all file metadata except the filename:

The filename is stored in the directory entry, which points to an inode. Multiple directory entries (hard links) can point to the same inode, giving a file multiple names.

# View inode information:
$ stat file.txt
File: file.txt
Size: 1024 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 1234567 Links: 2
Access: (0644/-rw-r--r--) Uid: (1000/user) Gid: (1000/user)

Practical Applications of Links

# 1. Software version management
$ ln -sfn /opt/java-17 /opt/java-current
export JAVA_HOME=/opt/java-current

# 2. Configuration management
$ ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/

# 3. Atomic deployment with symlinks
$ ln -sfn /var/www/app-v2.3.1 /var/www/current
$ systemctl restart webapp

# 4. Space-efficient backups with hard links
$ cp -al /home/user /backup/2025-11-07 # Hard link backup

# 5. Shared library management
$ ls -l /lib/x86_64-linux-gnu/libc.so.6
lrwxrwxrwx 1 root root 12 Oct 4 2024 libc.so.6 -> libc-2.31.so

Common Pitfalls and Issues

Security Considerations

Link Management Commands

# Create link:
$ ln [-s] source target

# Remove link (doesn't affect target unless last hard link):
$ rm linkname
$ unlink linkname

# Update symlink:
$ ln -sfn new-target existing-link

# Check link:
$ readlink linkname
$ ls -l linkname
$ stat linkname

# Find links:
$ find /path -type l # Find all symlinks
$ find /path -samefile original # Find all hard links to file

Best Practices

Related Commands