Files and directories
ln
Make links between files, symbolic (-s) or hard.
ln [OPTION...] TARGET [LINK_NAME]
A symbolic link (ln -s) is a tiny file that contains a path. Opening the link opens
whatever that path points to. It can point to a directory, across filesystems, or to something
that does not exist (a "dangling" link). Delete the target and the link breaks.
A hard link (ln without -s) is a second name for the same file: both names point to the
same inode and are fully equal. The data is freed only when the last name is removed. Hard links
cannot span filesystems and cannot point to directories.
The argument order matches cp: what exists first, the new name second. A relative symlink
target is resolved from the directory the link lives in, not from where you ran ln, which
is the source of most broken links.
Examples
Create a symbolic link
ln -s data/config.json config.json
ls -l config.json
head -3 config.json
lrwxrwxrwx 1 dev dev 16 Oct 31 20:20 config.json -> data/config.json
{
"app": "demo",
"version": "2.4.1", ls -l shows the link type l and its target. Reading the link reads the target file.
Link to a directory
ln -s src/lib lib
ls lib/
helpers.py
Symlinks can point at directories, so lib/ behaves like src/lib/.
Create a hard link
ln todo.txt tasks.txt
ls -li todo.txt tasks.txt
9821208 -rw-rw-r-- 2 dev dev 62 Oct 24 21:28 tasks.txt 9821208 -rw-rw-r-- 2 dev dev 62 Oct 24 21:28 todo.txt
Both names show the same inode number (first column) and a link count of 2. Neither is the "original"; editing one changes the other because they are the same file.
A hard link survives deleting the other name
ln todo.txt tasks.txt
rm todo.txt
cat tasks.txt
buy milk fix login bug write tests fix logout bug deploy v2.4
Removing todo.txt only removed one name. The data stays as long as any name (or open file
handle) refers to it.
A symlink breaks when its target goes away
ln -s notes.txt n
rm notes.txt
ls -l n
cat n
lrwxrwxrwx 1 dev dev 9 Oct 31 20:20 n -> notes.txt cat: n: No such file or directory
The link still exists and still says notes.txt, but there is nothing there, so reading it
fails with "No such file or directory".
Relative targets are relative to the link
ln -s data/users.csv src/users.csv
cat src/users.csv
cat: src/users.csv: No such file or directory
The link src/users.csv contains data/users.csv, which is looked up from src/, giving
src/data/users.csv: broken. The fix is the next example.
Let ln compute the relative path
ln -sr data/users.csv src/users.csv
ls -l src/users.csv
head -2 src/users.csv
lrwxrwxrwx 1 dev dev 17 Oct 31 20:20 src/users.csv -> ../data/users.csv id,name,email,dept,joined 1,Alice Moreau,alice@example.com,engineering,2021-04-12
-r (--relative) writes the target relative to the link's own directory, here
../data/users.csv, and the link works. Relative links keep working if the whole tree moves.
Creating a link over an existing file
ln -s notes.txt todo.txt
ln: failed to create symbolic link 'todo.txt': File exists
ln will not replace an existing file without being told to.
Repoint an existing symlink
ln -s logs/app.log current.log
ln -sfn logs/error.log current.log
ls -l current.log
lrwxrwxrwx 1 dev dev 14 Oct 31 20:20 current.log -> logs/error.log
-f removes the existing link first. -n matters when the old link points to a directory:
without it, ln would create the new link inside that directory. -sfn is the standard
way to switch a current link between releases.
Link several files into a directory
mkdir bin
ln -sr scripts/greet.sh scripts/backup.sh bin/
ls -l bin
total 1 lrwxrwxrwx 1 dev dev 20 Oct 31 20:20 backup.sh -> ../scripts/backup.sh lrwxrwxrwx 1 dev dev 19 Oct 31 20:20 greet.sh -> ../scripts/greet.sh
With a directory as the last argument, each link is created inside it under the target's
name. -r makes the targets correct relative to bin/.
Hard links to directories are not allowed
ln src src2
ln: src: hard link not allowed for directory
Directory hard links would allow loops in the tree, so the kernel forbids them. Use ln -s.
Common pitfalls
Argument order:
ln -s TARGET LINK. Swapping them (ln -s newname existing) fails with "File exists" or, worse, creates a link inside a directory.ln -s ../filestores exactly that text; it is resolved from the link's directory later. When unsure, useln -sror an absolute path.Tools differ on whether they follow links:
rm linkremoves the link,cp linkcopies the target,findanddudo not follow links unless told (-L).
GNU vs BSD and macOS
The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).
ln -r(--relative) is a GNU option; macOSlnlacks it, so compute the relative path yourself.BSD/macOS
lnuses-h(or-n) where GNU uses-nto avoid descending into an existing directory link;-sfnworks on both.
Options worth knowing
A selection, described in our own words. For the full list, see ln(1) or ln --help.
| Option | What it does |
|---|---|
-s, --symbolic | Make a symbolic link instead of a hard link. |
-f, --force | Remove an existing destination first. |
-n, --no-dereference | Treat an existing link to a directory as a file, not a place to create the link in. |
-r, --relative | With -s, store the target relative to the link's directory. |
-i, --interactive | Ask before replacing an existing file. |
-v, --verbose | Print each link created. |
-b | Back up an existing destination before replacing it. |
-t, --target-directory DIR | Create the links in DIR. |
-T, --no-target-directory | Treat LINK_NAME as a name, never a directory. |
-L, --logical | For a hard link to a symlink, link to its target. |
-P, --physical | For a hard link to a symlink, link to the symlink itself. |
Related
readlinkPrint where a symbolic link points, or with -f the fully resolved path of any file.realpathPrint the absolute, canonical path of a file, with symlinks, . and .. resolved.cpCopy files and directories, optionally keeping their timestamps, permissions and links.mvMove or rename files and directories.statShow a file's metadata (size, permissions, owner, inode, timestamps), or print chosen fields in your own format.