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 of find, though. But there are other options as well:

  • You can also exec test -e from within the find command:

    find . -type l ! -exec test -e {} \; -print
    
  • Even some grep trick could be better (i.e., safer) than find -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.