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, and assuming the GNU implementation of find
, it should rather look like this:
find . -xtype l
(xtype
is a test performed on a dereferenced link)
portably (though less efficiently), 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...
-type l
is redundant since-xtype l
will operate as-type l
on non-links. Sofind -xtype l
is probably all you need. Thanks for this approach. – quornian Nov 17 '12 at 21:56find -xtype l
is enough. The only difference is in the number of system calls performed by each command (which indicatesfind -type l -xtype l
should be faster). But I guess this would make a difference only on a large filesystem trees. – rozcietrzewiacz Nov 20 '12 at 20:08-xtype l
works.find . -type l -xtype l
means "find all the symlinks to symlinks", rather than, "find all the symlinks to files that don't exist", right? – Flimm Oct 07 '14 at 12:53/proc/XXX/exe
link is broken. For this, usetest -e "$(readlink /proc/XXX/exe)"
. – qwertzguy Jan 08 '15 at 21:37find . -xtype l
means "find all symlinks whose (ultimate) target files are symlinks". But the ultimate target of a symlink cannot be a symlink, otherwise we can still follow the link and it is not the ultimate target. Since there is no such symlinks, we can define them as something else, i.e. broken symlinks. – weakish Apr 08 '16 at 04:57-xtype
follows the chain of symbolic links and evaluates the file at the end, which can only be a symbolic link in case it is broken. – Joó Ádám Apr 13 '16 at 16:40l
, is less confusing to me. – weakish Apr 22 '16 at 12:19-L
hack but rather to (blindly) removing broken symlinks in general. – Alois Mahdal Jul 15 '16 at 00:22-L
was risky and that's why I found this. On breaking systems from symlinks I recall doing something (but I was able to salvage it because it was an experiment of sort) with/dev/null
years ago. I needn't elaborate on why there was a symlink to it - it was in any case risky; it was not to do withfind
but something about recursively following the link nonetheless (or rather in this case dereferencing the link). I have this memory I've played with the same functionality before but I don't know for sure and it's not really important. (1/2) – Pryftan Oct 01 '19 at 14:27-xtype l
some comments on the options that change how symlinks infind
go in order to find broken symlinks: (1) Because of how-L
works don't use that option for broken symlink tests. (2)-P
is the default and-xtype l
works fine to find broken symlinks. But (3)-H
appears to work but I do not know if it has any implications in different circumstances. Thus because what you and the commentator suggest it seems what needs to be done is only use-xtype l
. Oh and correct:-xtype
is not specified in POSIX. (2/2) – Pryftan Oct 01 '19 at 14:30-xtype
isn't available on all systems e.g. macOS the second option,find . -type l ! -exec test -e {} \; -print
seems to me to be the proper answer. However - and maybe this is an artefact of books of old that I read aeons ago - I think it should actually be:find . -type l \! -exec test -e '{}' \; -print
. However if you want to act on each file maybe-exec
is a better idea? Or if you have GNU find then-print0 | xargs -0
more so. – Pryftan Oct 01 '19 at 14:42{}
with"$(readlink /proc/XXX/exe)"
as infind . -type l ! -exec test -e "$(readlink {})" \; -print
? – Setaa Aug 27 '20 at 00:24test
, to adapt the fullfind
command above, what you wrote seems correct. – qwertzguy Aug 27 '20 at 21:51find . -xdev -type l -xtype l
vs.find . -xdev -xtype l
, I've found that the first test runs about 5 times faster than the last, while giving same results. – AnrDaemon Jan 15 '24 at 15:05