Delete all broken symbolic links with a line?
BashShellUnixSymlinkBash Problem Overview
For a given folder, how can I delete all broken links within it?
I found this answer that shows how to delete one broken link, but I can't put that together in only one line. Is there a one-liner for this?
A broken symbolic is a link that points to a file/folder that doesn't exists any longer.
Bash Solutions
Solution 1 - Bash
Here's a POSIX way of deleting all broken symbolic links in the current directory, without recursion. It works by telling find
to traverse symbolic links (-L
), but stopping (-prune
) at every directory-or-symbolic-link-to-such.
find -L . -name . -o -type d -prune -o -type l -exec rm {} +
You can also use a shell loop. The test -L
matches symbolic links, and -e
matches existing files (excluding broken symlinks).
for x in * .[!.]* ..?*; do if [ -L "$x" ] && ! [ -e "$x" ]; then rm -- "$x"; fi; done
If you want to recurse into subdirectories, this technique doesn't work. With GNU find (as found on non-embedded Linux and Cygwin), you can use the -xtype
predicate to detect broken symbolic links (-xtype
uses the type of the target for symbolic links, and reports l
for broken links).
find -xtype l -delete
POSIXly, you need to combine two tools. You can use find -type l -exec …
to invoke a command on each symbolic link, and [ -e "$x" ]
to test whether that link is non-broken.
find . -type l -exec sh -c 'for x; do [ -e "$x" ] || rm "$x"; done' _ {} +
The simplest solution is to use zsh. To delete all broken symbolic links in the current directory:
rm -- *(-@D)
The characters in parentheses are glob qualifiers: -
to dereference symlinks, @
to match only symlinks (the combination -@
means broken symlinks only), and D
to match dot files. To recurse into subdirectories, make that:
rm -- **/*(-@D)
Solution 2 - Bash
Simple answer based on the answer you linked (for a given directory, $DIR
):
find -L $DIR -maxdepth 1 -type l -delete
Solution 3 - Bash
For MAC, do a dry run as follows:-
DIR=<some path>
find -L $DIR -maxdepth 1 -type l -print
Now, you can prune the old symlinks as follows:-
for f in `find -L $DIR -maxdepth 1 -type l`; do unlink $f; done
Solution 4 - Bash
From man find
EXAMPLES:
find -L /usr/ports/packages -type l -exec rm -- {} +
> Delete all broken symbolic links in /usr/ports/packages.
Solution 5 - Bash
Answer based on the accepted answer to the question question ["How can I find broken symlinks"][1]:
find . -type l -! -exec test -e {} \; -print | xargs rm
[1]: https://unix.stackexchange.com/a/38691/83167 "How can I find broken symlinks"
Solution 6 - Bash
The package symlinks
is pre-installed on many distributions (including Ubuntu 16.04 & Fedora 25) and has some really useful features, one of which does precisely what you're looking for:
symlinks -d ./
-d == delete dangling links
Solution 7 - Bash
You could use readlink
to determine if a symlink is broken or not.
The following would list all the broken symlinks in a given directory (and subdirectories):
find . -type l -exec sh -c 'readlink -f "{}" 1>/dev/null || echo "{}"' -- "{}" \;
Replace echo
with rm
to get rid of the broken ones!
(I've redirected the output of readlink
to /dev/null
so as to avoid confusion; it'd list the target for the symlinks.)
Solution 8 - Bash
You can try using rmlint.
First, change directory to the folder that contains broken symlinks, and then run the following commands to find bad symlinks pointing nowhere:
rmlint --types="badlinks"
Then rmlint
will create a bash script rmlint.sh
in your current directory and print a list of bad symlinks in your terminal. To delete all the bad symlinks in your current directory, you can run
./rmlint.sh
Not exactly one liner, but it is very easy to use.
Solution 9 - Bash
This answer is based on @sanmiguel's but with fd
fd -tl -L $DIR -X rm