ln — Create Hard Links and Symlinks

Make links between files — create hard links and symbolic (soft) links to files and directories, giving one file multiple names or shortcuts.

ln creates links between files – either a symbolic link (symlink) that points to a path like a shortcut, or a hard link, where multiple names reference the same inode and therefore the same data. The biggest gotcha is argument order: it is always ln -s <target> <link>, that is the target first and the name of the new link second – swap them and you create the link in the wrong place. This guide covers symlinks and hard links, the crucial difference between them, and common patterns such as atomic deployments and dotfile management.

ln -s <target> <link> — Create a symbolic link pointing to target.

ln -s /var/log/syslog ~/syslog

ln -s <target> — Create a symlink in the current directory with the same name as target.

ln -s /etc/nginx/nginx.conf

ln -sf <target> <link> — Create or overwrite a symbolic link (force).

ln -sf /usr/bin/python3.12 /usr/bin/python3

ln -sn <target> <link> — Do not dereference link if it is a symlink to a directory. Useful for replacing directory symlinks.

ln -sfn /var/www/release-2.0 /var/www/current

ln -s <target1> <target2> <dir> — Create multiple symlinks in a target directory.

ln -s /opt/bin/app1 /opt/bin/app2 /usr/local/bin/

ln <target> <link> — Create a hard link. Both names point to the same inode and data.

ln important.txt important-backup.txt

ln <target> — Create a hard link in the current directory with the same name.

ln /data/shared-config.txt

ln <target1> <target2> <dir> — Create hard links to multiple files in a target directory.

ln file1.txt file2.txt /backup/

ln -f <target> <link> — Force creation by removing existing destination file.

ln -f newdata.txt data.txt

ln <target> <link> — Hard link: same inode, same filesystem only, survives target rename/move.

ln original.txt hardlink.txt

ln -s <target> <link> — Symbolic link: separate inode, cross-filesystem, breaks if target is removed.

ln -s original.txt symlink.txt

ls -li <file> — Show inode number. Hard links share the same inode as their target.

ls -li original.txt hardlink.txt

stat <file> — Show detailed file info including inode and hard link count.

stat original.txt

Options

ln -v <target> <link> — Verbose mode. Print each link as it is created.

ln -sv /opt/app/config.yml ~/config.yml

ln -i <target> <link> — Interactive mode. Prompt before overwriting existing files.

ln -si /new/target existing-link

ln -b <target> <link> — Create a backup of existing destination file before overwriting.

ln -sb /new/target existing-link

ln -S <suffix> <target> <link> — Set backup suffix (default: ~) when using -b.

ln -sb -S .bak /new/target existing-link

ln -r -s <target> <link> — Create a relative symbolic link instead of absolute.

ln -rs /var/www/shared/assets /var/www/app/assets

ln -t <dir> -s <target> — Specify the link directory explicitly with -t.

ln -t /usr/local/bin -s /opt/app/bin/tool

readlink <link> — Print the target of a symbolic link.

readlink /usr/bin/python3

readlink -f <link> — Print the fully resolved absolute path (follows all symlinks).

readlink -f /usr/bin/python

ls -l <link> — Show symlink target in long listing format (-> target).

ls -l /usr/bin/python3

file <link> — Show whether a path is a symlink and where it points.

file /usr/bin/python3

unlink <link> — Remove a symbolic or hard link (does not affect target).

unlink ~/syslog

rm <link> — Remove a link. Same as unlink for single files.

rm ~/syslog

find . -type l — Find all symbolic links in the current directory tree.

find /etc -type l

find . -xtype l — Find broken symbolic links (target does not exist).

find /usr/local/bin -xtype l

Common Patterns

ln -sfn <release-dir> <current> — Atomic deployment: switch a symlink to a new release directory.

ln -sfn /var/www/releases/v2.1 /var/www/current

ln -s /path/to/dotfile ~/.dotfile — Dotfile management: symlink config files from a central repo.

ln -s ~/dotfiles/.vimrc ~/.vimrc

ln -s $(which <cmd>) /usr/local/bin/<alias> — Create a command alias via symlink.

ln -s $(which python3) /usr/local/bin/python

for f in <dir>/*; do ln -s "$f" .; done — Create symlinks to all files in a directory.

for f in /opt/config/*; do ln -s "$f" .; done

ln -s /dev/null <file> — Suppress a file by pointing it to /dev/null (e.g. unwanted logs).

ln -sf /dev/null ~/.bash_history

find . -type l ! -exec test -e {} \; -print — Find and list all broken symlinks.

find /usr/local -type l ! -exec test -e {} \; -print

find . -maxdepth 1 -type l -delete — Remove all symlinks in the current directory (non-recursive).

find . -maxdepth 1 -type l -delete

Conclusion

ln is small but powerful – the key is keeping the two link types apart: a symlink (-s) is merely a reference to a path, works across filesystem boundaries, but breaks when the target disappears; a hard link is an equal second name for the same data, stays valid even after the target is renamed, but is confined to one filesystem and is not allowed for directories. Remember the argument order ln -s <target> <link>, and use -sfn to atomically switch directory symlinks (the classic deployment trick). When in doubt about what points where, check the inode and link count with ls -li and stat.

Further Reading

  • cp – copy files and directories
  • ls – list directory contents and inodes
  • stat – show detailed file and inode information