The basic command for creating a symbolic link (a “symlink” or “soft link”) to a folder or file is ln -s:
1 2 3 4 5 6 7 8 | ln -s /home/ronald/somefolder /home/ronald/newfolder # or if your current directory is already /home/ronald: cd /home/ronald ln -s somefolder newfolder # general form: ln -s existingSourceFolder newLinkedFolder |
The first argument is the target (what the link points at), the second is the link name (what gets created). I get this order backwards every time — the mnemonic that finally stuck is “ln -s is like cp: source first, destination second.”
To remove all symlinks in the current directory (and only symlinks — leaving regular files and directories untouched):
1 | find . -maxdepth 1 -type l -exec rm -f {} \; |
-type l is the filter that matches symlinks specifically. -maxdepth 1 keeps the search from descending into subdirectories, so you only kill the symlinks at the top level.
A few useful additions: symlinks have sharp edges.
Symlinks look simple — “a file that points to another file” — but they have a handful of behaviors that catch people out. The ones below are the ones I’ve actually been bitten by.
Symlinks vs. hard links. The -s in ln -s is the difference. Without it, you get a hard link: a second directory entry pointing to the same inode. Hard links don’t break if you move or rename the original (because both names refer to the same data). Symlinks store a path and break if the target moves. Hard links can’t span filesystems and can’t point to directories (the kernel forbids it to prevent loops); symlinks can do both.
Inspecting a symlink. A few different tools answer different questions:
1 2 3 4 5 | ls -l newfolder # shows: newfolder -> /home/ronald/somefolder readlink newfolder # prints just the target: /home/ronald/somefolder readlink -f newfolder # follows all symlinks, prints absolute target realpath newfolder # same idea as readlink -f, slightly different edge cases stat newfolder # full metadata; "File: newfolder -> ..." |
readlink -f is the one I reach for most — it tells you where a symlink ultimately resolves, even through chains of symlinks-pointing-to-symlinks.
Relative vs. absolute targets. The path you pass as the target is stored verbatim. If you write a relative target, it’s resolved relative to the directory the link lives in, not the directory you ran the command from. This trips people up:
1 2 3 4 5 6 | cd /tmp ln -s ../etc/hosts mylink # mylink points to ../etc/hosts # which from /tmp resolves to /etc/hosts ✓ mv mylink /var/log/ # now /var/log/mylink points to ../etc/hosts # which resolves to /var/etc/hosts ✗ broken |
Rule of thumb: use absolute paths unless you specifically want the link to follow when both source and link move together (common pattern: shipping a relative symlink inside a tarball or git repo).
The rm -rf on a symlink-to-directory trap. This one is genuinely dangerous:
1 2 3 4 | ln -s /important/data ./mydata rm -rf mydata # removes the symlink only — /important/data is safe rm -rf mydata/ # WITH trailing slash: rm follows the link and # recursively deletes /important/data |
The trailing slash changes the command from “delete this symlink” to “delete what’s inside the directory the symlink points to.” If you’re in the habit of tab-completing paths, your shell often appends the slash for you. Be deliberate when removing symlinks to directories.
Updating an existing symlink. By default ln -s refuses to overwrite. The flags vary depending on what you’re replacing:
1 2 3 4 | ln -sf newtarget mylink # works for symlinks to files ln -sfn newtarget mydirlink # for symlinks to directories — without -n, # ln creates a NEW link INSIDE the existing # directory link instead of replacing it |
Forgetting -n on a directory symlink is one of those bugs that’s invisible until you wonder why your link “didn’t take” — and meanwhile a stray newtarget entry is hiding in the linked directory.
Finding broken symlinks. Symlinks happily survive their targets being deleted. To find ones that no longer point anywhere valid:
1 2 | find . -xtype l # broken symlinks under current dir find / -xtype l 2>/dev/null # the same, system-wide (slow) |
-xtype l means “the symlink’s target is not a real file/directory we can stat” — i.e. the link is dangling. Useful as a periodic sanity check after you’ve moved or removed a directory that other things might have linked to.
Finding what links to a given target. The reverse question — “is anything pointing at this file?” — has no fast answer; you have to scan:
1 2 | find / -lname "*somefolder*" 2>/dev/null # by target pattern find / -samefile /home/ronald/somefolder 2>/dev/null # exact same inode |
The first form matches the symlink’s stored target string; the second works for hard links (same inode). There’s no equivalent of “give me everything that resolves to this path,” because resolving every symlink on the system would be expensive — you’d be running readlink -f on every link in the search tree.