How can I find broken symlinks
I'd strongly suggest not to use find -L
for the task (see below for explanation). Here are some other ways to do this:
If you want to use a "pure
find
" method, it should rather look like this:find . -xtype l
(
xtype
is a test performed on a dereferenced link) This may not be available in all versions offind
, though. But there are other options as well:You can also exec
test -e
from within thefind
command:find . -type l ! -exec test -e {} \; -print
Even some
grep
trick could be better (i.e., safer) thanfind -L
, but not exactly such as presented in the question (which greps in entire output lines, including filenames):find . -type l -exec sh -c 'file -b "$1" | grep -q ^broken' sh {} \; -print
The find -L
trick quoted by solo from commandlinefu looks nice and hacky, but it has one very dangerous pitfall: All the symlinks are followed. Consider directory with the contents presented below:
$ ls -l
total 0
lrwxrwxrwx 1 michal users 6 May 15 08:12 link_1 -> nonexistent1
lrwxrwxrwx 1 michal users 6 May 15 08:13 link_2 -> nonexistent2
lrwxrwxrwx 1 michal users 6 May 15 08:13 link_3 -> nonexistent3
lrwxrwxrwx 1 michal users 6 May 15 08:13 link_4 -> nonexistent4
lrwxrwxrwx 1 michal users 11 May 15 08:20 link_out -> /usr/share/
If you run find -L . -type l
in that directory, all /usr/share/
would be searched as well (and that can take really long)1. For a find
command that is "immune to outgoing links", don't use -L
.
1 This may look like a minor inconvenience (the command will "just" take long to traverse all /usr/share
) – but can have more severe consequences. For instance, consider chroot environments: They can exist in some subdirectory of the main filesystem and contain symlinks to absolute locations. Those links could seem to be broken for the "outside" system, because they only point to proper places once you've entered the chroot. I also recall that some bootloader used symlinks under /boot
that only made sense in an initial boot phase, when the boot partition was mounted as /
.
So if you use a find -L
command to find and then delete broken symlinks from some harmless-looking directory, you might even break your system...
The symlinks
command from http://www.ibiblio.org/pub/Linux/utils/file/symlinks-1.4.tar.gz can be used to identify symlinks with a variety of characteristics. For instance:
$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
As rozcietrzewiacz has already commented, find -L
can have unexpected consequence of expanding the search into symlinked directories, so isn't the optimal approach. What no one has mentioned yet is that
find /path/to/search -xtype l
is the more concise, and logically identical command to
find /path/to/search -type l -xtype l
None of the solutions presented so far will detect cyclic symlinks, which is another type of breakage. this question addresses portability. To summarize, the portable way to find broken symbolic links, including cyclic links, is:
find /path/to/search -type l -exec test ! -e {} \; -print
For more details, see this question or ynform.org. Of course, the definitive source for all this is the findutils documentaton.