55

I have created symlinks to a large amount of logfiles. The syntax of the logfiles is yyyymmdd.log.gz.

To simplify things I use a simple sequence without parsing it with date:

for dd in $(seq -w 20150101 20151231) ; do 
     ln -s $origin/$dd.log.gz $target/$dd.log.gz
done

How do I get rid of all the broken symlinks I just created in a single fell swoop?

6 Answers 6

110

This simple one-liner does the job quite fast. It requires GNU Findutils:

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 lower case L (as in link) ;)

3
  • 4
    Use -print -delete if you would like to display a list of what is being deleted. Commented Mar 27, 2023 at 17:15
  • Printing the deleted links helps a lot! Thank you :) Commented Nov 22, 2023 at 7:58
  • really the best answer. works efficiently and completely and only on broken links. without the -delete it just lists them. Commented Dec 25, 2023 at 17:05
18
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.

2
  • 1
    Works on macOs. Thanks for considering alternate flavors. Commented Jul 14, 2021 at 0:10
  • An alternative to prompt the user for confirmation is to use the -ok action instead of -exec rm -i (probably a GNU feature as well): find /path -xtype l -ok rm {} \; Commented Jan 28, 2024 at 4:40
3

Rob Current’s answer is certainly helpful and works.

A further example can be found via man find on macOS for deleting all broken symlinks in a given directory.

Say you have a directory /usr/ports/packages containing broken symlinks to other files or directories that have either moved or been deleted, the following command will remove all symlinks for which the previously linked file location no longer exists.

EXAMPLES
    The following examples are shown as given to the shell:
    ...
    
    find -L /usr/ports/packages -type l -exec rm -- {} +
           Delete all broken symbolic links in /usr/ports/packages.
     ...
BSD                           September 28, 2011                           BSD

The -L switch (as per man find) causes the file information and file type returned for each symbolic link to be those of the file referenced by the link, not the link itself. If, however, the referenced file does not exist, the file information and type will be for the link itself.

The -type l switch limits the files found to those which are symbolic links.

What follows the -exec switch is the command to execute for matching files.

The -- switch causes rm, which uses getopt(3) to parse its arguments, to stop processing flag options afterwards.

As explained by man find, the syntax exec utility [argument ...] {} + has the same effect as -exec, except that ``{}'' is replaced with as many pathnames as possible for each invocation of the utility. This behaviour is similar to that of xargs(1).

Hope that’s helpful.

0
2

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

0

If all the broken links were created by an error cmd, at a given timestamp, then below works well.

ls -lrt | grep "Sep 17 15:06" | awk '{print $9}' | xargs \rm
0

Given the details of the question, you may instead want:

find . -maxdepth 1 -xtype l -delete 
1
  • This is the same as the accepted answer but with the addition of -maxdepth 1.   Trivial modifications like that should be submitted, not as new, separate answers, but as comments. Commented Dec 20, 2024 at 20:20

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.