How to delete broken symlinks in one go?

This simple one liner does the job quite fast, requires GNU find:

find . -xtype l -delete

A bit of explanation:

-xtype l tests for links that are broken (it is the opposite of -type)

-delete deletes the files directly, no need for further bothering with xargs or -exec

NOTE: -xtype l means -xtype low case L (as in link) ;)

GNU Findutils: Find


find -L /path -type l -exec rm -i {} \;

With -L, find tries to follow symbolic links to evaluate the -type test. If it succeeds in following the link, then the link is not broken, and the -type l test will be false (as it is evaluated for the thing that the link resolves to). If it fails in following the link, then the link is broken and the -type l test will be true.

If the -type l test succeeds, then the -exec rm {} \; removes the broken link.

The suggestion to use -xtype l is a GNUism, primarily for Linux users, and won't work on non-GNU UNIX systems like Solaris, FreeBSD, etc.


With zsh (you're actually using zsh syntax in your code; with bash, you'd need to quote those variables):

rm -- $target/*(-@)

Or:

rm -- $target/<20150101-20151231>.log.gz(-@)

*(@) matches the files of type symlink. *(-@) are the ones that are still of type symlink after symlink resolution (that is, those for which the target of the symlink can't be resolved). That's equivalent to GNU find's -xtype l.

In zsh and with GNU ln, you'd rather write your loop as:

ln -srt $target -- $origin/<20150101-20151231>.log.gz

Which would also work even if $origin contains a relative path (and creates relative symlinks which reduces the risk of symlinks to be broken if some path components of the origin (the ones that are common with that of the target) are renamed in the future).

Tags:

Bash

Symlink

Find