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.
Symbolic Links (Soft Links)
ln -s <target> <link> — Create a symbolic link pointing to target.
ln -s /var/log/syslog ~/syslogln -s <target> — Create a symlink in the current directory with the same name as target.
ln -s /etc/nginx/nginx.confln -sf <target> <link> — Create or overwrite a symbolic link (force).
ln -sf /usr/bin/python3.12 /usr/bin/python3ln -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/currentln -s <target1> <target2> <dir> — Create multiple symlinks in a target directory.
ln -s /opt/bin/app1 /opt/bin/app2 /usr/local/bin/Hard Links
ln <target> <link> — Create a hard link. Both names point to the same inode and data.
ln important.txt important-backup.txtln <target> — Create a hard link in the current directory with the same name.
ln /data/shared-config.txtln <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.txtHard Links vs Symbolic Links
ln <target> <link> — Hard link: same inode, same filesystem only, survives target rename/move.
ln original.txt hardlink.txtln -s <target> <link> — Symbolic link: separate inode, cross-filesystem, breaks if target is removed.
ln -s original.txt symlink.txtls -li <file> — Show inode number. Hard links share the same inode as their target.
ls -li original.txt hardlink.txtstat <file> — Show detailed file info including inode and hard link count.
stat original.txtOptions
ln -v <target> <link> — Verbose mode. Print each link as it is created.
ln -sv /opt/app/config.yml ~/config.ymlln -i <target> <link> — Interactive mode. Prompt before overwriting existing files.
ln -si /new/target existing-linkln -b <target> <link> — Create a backup of existing destination file before overwriting.
ln -sb /new/target existing-linkln -S <suffix> <target> <link> — Set backup suffix (default: ~) when using -b.
ln -sb -S .bak /new/target existing-linkln -r -s <target> <link> — Create a relative symbolic link instead of absolute.
ln -rs /var/www/shared/assets /var/www/app/assetsln -t <dir> -s <target> — Specify the link directory explicitly with -t.
ln -t /usr/local/bin -s /opt/app/bin/toolManaging Links
readlink <link> — Print the target of a symbolic link.
readlink /usr/bin/python3readlink -f <link> — Print the fully resolved absolute path (follows all symlinks).
readlink -f /usr/bin/pythonls -l <link> — Show symlink target in long listing format (-> target).
ls -l /usr/bin/python3file <link> — Show whether a path is a symlink and where it points.
file /usr/bin/python3unlink <link> — Remove a symbolic or hard link (does not affect target).
unlink ~/syslogrm <link> — Remove a link. Same as unlink for single files.
rm ~/syslogfind . -type l — Find all symbolic links in the current directory tree.
find /etc -type lfind . -xtype l — Find broken symbolic links (target does not exist).
find /usr/local/bin -xtype lCommon 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/currentln -s /path/to/dotfile ~/.dotfile — Dotfile management: symlink config files from a central repo.
ln -s ~/dotfiles/.vimrc ~/.vimrcln -s $(which <cmd>) /usr/local/bin/<alias> — Create a command alias via symlink.
ln -s $(which python3) /usr/local/bin/pythonfor 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" .; doneln -s /dev/null <file> — Suppress a file by pointing it to /dev/null (e.g. unwanted logs).
ln -sf /dev/null ~/.bash_historyfind . -type l ! -exec test -e {} \; -print — Find and list all broken symlinks.
find /usr/local -type l ! -exec test -e {} \; -printfind . -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
- GNU coreutils: ln invocation – official reference for every option
- Linux man page: ln(1) – the canonical manual page