shell – How to Find Broken Symlinks

findshellsymlink

Is there a way to find all symbolic links that don't point anywere?

find ./ -type l

will give me all symbolic links, but makes no distinction between links that go somewhere and links that don't.

I'm currently doing:

find ./ -type l -exec file {} \; | grep broken

But I'm wondering what alternate solutions exist.

Best Answer

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...