How can I find broken symlinks

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.

Asked By: gabe.


I believe adding the -L flag to your command will allow you do get rid of the grep:

$ find -L . -type l

from the manual:


Cause the file information and file type (see stat(2)) returned
for each symbolic link to be those of the file referenced by the
link, not the link itself. If the referenced file does not exist,
the file information and type will be for the link itself.

Answered By: kwarrick

The symlinks command from can be used to identify symlinks with a variety of characteristics. For instance:

$ rm a
$ ln -s a b
$ symlinks .
dangling: /tmp/b -> a
Answered By: Sam Morris

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…

Answered By: rozcietrzewiacz

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 Of course, the definitive source for all this is the findutils documentaton.

Answered By: pooryorick

If you need a different behavior whether the link is broken or cyclic you can also use %Y with find:

$ touch a
$ ln -s a b  # link to existing target
$ ln -s c d  # link to non-existing target
$ ln -s e e  # link to itself
$ find . -type l -exec test ! -e {} ; -printf '%Y %pn' 
   | while read type link; do
         case "$type" in
         N) echo "do something with broken link $link" ;;
         L) echo "do something with cyclic link $link" ;;
do something with broken link ./d
do something with cyclic link ./e

This example is copied from this post (site deleted).


Answered By: andy

find -L . -type l |xargs symlinks will give you info whether the link exists or not on a per foundfile basis.

Answered By: Alexander Oh

This will print out the names of broken symlinks in the current directory.

for l in $(find . -type l); do cd $(dirname $l); if [ ! -e "$(readlink $(basename $l))" ]; then echo $l; fi; cd - > /dev/null; done

Works in Bash. Don’t know about other shells.

Answered By: conradkleinespel

I use this for my case and it works quite well, as I know the directory to look for broken symlinks:

find -L $path -maxdepth 1 -type l

and my folder does include a link to /usr/share but it doesn’t traverse it.
Cross-device links and those that are valid for chroots, etc. are still a pitfall but for my use case it’s sufficient.

Answered By: Iskren

Simple no-brainer answer, which is a variation on OP’s version. Sometimes, you just want something easy to type or remember:

find . | xargs file | grep -i "broken symbolic link"

Or, if you need to handle NULL terminators:

find . -print0 | xargs -0 file | grep -i "broken symbolic link"
Answered By: trinth

For zsh users:

rm -v -- **/*(-@)

To also remove hidden ones:

rm -v -- **/*(D-@)

from zsh user guide (search for broken symlinks)

Answered By: murla

Most comprehensive (imho) command to find broken symlinks without crossing partition bounds. Note, that symlink arguments must be containing directories, not symlinks themselves.

find . -xdev -type d 
| stdbuf -oL xargs -d 'n' symlinks 
| stdbuf -oL grep -e '^dangling'
Answered By: Nikita Zlobin

I took

find ./ -type l -exec file {} ; | that.awk

and piped it into an Awk script, that way you can do whatever.

#!/bin/awk -f
# ==============================================================================
# ==============================================================================
   sub(/^ /,"",$2)               # remove leading spc
   p=index($2,"to")              # 'to' pointer
   s=substr($2,1,p-2)            # status
   t=substr($2,p+3)              # target

      case /^broken.*/ :
         printf("%"w"s %sn","target:",t)
         printf("%"w"s %sn","source:",$1)
         printf("%"w"s %sn","status:",s)
#      default:
#         printf("n")
#         printf("%"w"s %sn","target:",t)
# ==============================================================================
# ==============================================================================
# functions
# ==============================================================================
Answered By: liz

find . -xtype l will skip broken links pointing to files in inaccessible directories. You can just search for links to inaccessible files:

find . -type l ! -readable

This works correctly for cyclic symlinks and is also more efficient than using -exec test … with find command.

Answered By: ArturZ
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.