34

On this question or on this one (for example) you will get solutions on how to look for symlinks pointing to a given directory (let's call it /dir1), while I am interested to symbolic links possibly pointing to any file/folder inside /dir1.

I want to delete such directory but I am not sure that I am safe to do so, as on an other directory (let's call it /dir2), I may have symlinks pointing to inner parts of /dir1.

Further, I may have created these symlinks using absolute or relative paths. My only help is that I know the symlinks I want to check are on a mounted filesystem, on /dir2.

4 Answers 4

30

You can find all the symbolic links using:

find / -type l 

you might want to run this as root in order to get to every place on the disc.

You can expand these using readlink -f to get the full path of the link and you should be able to grep the output against the target directory that you are considering for deletion:

find / -type l -exec readlink -f {} + | grep -F /dir2

Using find / -type l -printf '%l\n' doesn't work as you get relative links like ../tmp/xyz which might be pointing to your target dir, but are not matched because they are not fully expanded.

3
  • 2
    In case of subtree it can be useful to follow symlinks: find -L /subtree -xtype l -exec readlink -f {} +
    – ruvim
    Nov 30, 2017 at 11:52
  • 1
    What does the + do here?
    – Liam
    Jul 21, 2020 at 15:24
  • 2
    @Liam It tells find that the -exec is finished and that multiple arguments should be passed to the command (readlink) at the position of {} (you can also finish with ; (which needs to be escaped in many shells), to invoke the command with a single argument, which is much slower to execute.
    – Anthon
    Jul 21, 2020 at 20:03
17

In my case, the accepted answer wasn't useful (because it didn't output the link source). Here is what worked for me.

I worked around it using two -exec clauses:

find /home/ -type l -exec readlink -nf {} ';' -exec echo " -> {}" ';' | grep "/dir2"
2
  • 3
    This works, but the arrow (->) is misleading, it should point from right to left (<-). Oct 5, 2020 at 13:54
  • 1
    Rather than flipping the arrow, this would print the expected output: find /home/ -type l -printf '%p -> ' -exec readlink -f {} ';' | grep "/dir2"
    – MichaelK
    Feb 23, 2021 at 20:56
3

With zsh:

print -rC1 /dir2/**/*(ND@e['[[ $REPLY:P = /dir1(/*|) ]]'])

Broken down:

  • print -rC1: prints its arguments raw on 1 Column. Here, the arguments will be those generated from the following glob. Replace with ls -ld to get more information about each symlink¹
  • **/: any level of subdirectories (recursive globbing)
  • *: file with any name (made of any number of characters, though zsh's * like that of most shells will also allow non-characters).
  • (...): glob qualifiers to further qualify the matching on other criteria than just the name of the files
  • N: enable nullglob for that one glob (won't fail if there's no match, just pass an empty list to print which will print nothing).
  • D: enable dotglob: also consider hidden files.
  • @: restrict to files of type symlink.
  • e['code']: select files for which the code evaluates to true. Inside the code, the file being considered is stored in $REPLY.
  • $REPLY:P: gets the absolute and canonical (symlink free) path to the file (similar to what the realpath() standard function does).
  • [[ string = pattern ]] returns true if the string matches the pattern (from ksh).
  • /dir1(/*|) as a pattern matches on /dir1 alone or /dir1/ followed by anything.

¹ with the caveat that if there's not matching file, that will list the current working directory. With ls, it would be better to remove the N glob qualifier

0

Depending on your circumstances, you could delete the directory, then delete any resultant invalid symlinks with the following:

find -xtype l -delete

The xtype test returns 'l' if the symlink is broken.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.