list all symbolic links to valid directories only with find

7,235

Solution 1

With GNU find (the implementation on non-embedded Linux and Cygwin):

find /search/location -type l -xtype d

With find implementations that lack the -xtype primary, you can use two invocations of find, one to filter symbolic links and one to filter the ones that point to directories:

find /search/location -type l -exec sh -c 'find -L "$@" -type d -print' _ {} +

or you can call the test program:

find /search/location -type l -exec test {} \; -print

Alternatively, if you have zsh, it's just a matter of two glob qualifiers (@ = is a symbolic link, - = the following qualifiers act on the link target, / = is a directory):

print -lr /search/location/**/*(@-/)

Solution 2

Try:

find /search/location -type l -exec test -e {} \; -print 

From man test:

   -e FILE
          FILE exists

You might also benefit from this U&L answer to How can I find broken symlinks; be sure to read the comments too.

Edit: test -d to check if "FILE exists and is a directory"

find /search/location -type l -exec test -d {} \; -print 
Share:
7,235

Related videos on Youtube

muffel
Author by

muffel

Updated on September 18, 2022

Comments

  • muffel
    muffel almost 2 years

    I can use

    find /search/location -type l
    

    to list all symbolic links inside /search/location.

    How do I limit the output of find to symbolic links that refer to a valid directory, and exclude both, broken symbolic links and links to files?

  • muffel
    muffel over 9 years
    thank you, but this finds links to files as well
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' over 9 years
    Don't parse the output of find. This breaks on file names containing whitespace or wildcard characters. For the same reason, put double quotes around variable substitutions. See unix.stackexchange.com/questions/131766/…
  • Upe
    Upe almost 3 years
    find . -type l -exec sh -c 'find "$@" -L -type d -print' _ {} + yielded find: unknown predicate `-L' for me. moving the -L in the second find invocation before the "$@" made this work.