61

I run find and iterate through the results with [ \( -L $F \) ] to collect certain symbolic links.

I am wondering if there is an easy way to determine if the link is broken (points to a non-existent file) in this scenario.

Here is my code:

FILES=`find /target/ | grep -v '\.disabled$' | sort`

for F in $FILES; do
    if [ -L $F ]; then
        DO THINGS
    fi
done
Te Ri
  • 177
  • 1
  • 5
zoltanctoth
  • 2,788
  • 5
  • 26
  • 32

7 Answers7

61
# test if symlink is broken (by seeing if it links to an existing file)
if [ ! -e "$F" ] ; then
    # code if the symlink is broken
fi
Ross Smith II
  • 11,799
  • 1
  • 38
  • 43
Roger
  • 690
  • 6
  • 2
  • 5
    Note that the code will also be executed if the file does not exist at all. It is fine with `find` but in other scenarios (such as globs) should be combined with -h to handle this case, for instance `[ -h "$F" -a ! -e "$F" ]`. – Calimo Apr 18 '17 at 19:50
  • 2
    You're not really testing the symbolic link with this approach. – Sridhar Sarnobat Jul 13 '17 at 22:36
  • @Calimo There is no difference. – Melab Jul 24 '17 at 15:22
  • 6
    @Melab wrong... Please test your assumptions before commenting: https://git.io/fx95w This answer is INCORRECT. – hasufell Oct 27 '18 at 07:04
  • Didn't work for me. I created a link, then I removed the target file and the check was still returning true – cisk Jan 10 '20 at 10:10
  • @Camilo solution worked for me in a more general case (not with find) – mikemtnbikes Jan 12 '21 at 22:04
  • FYI all: see `man test` or `man [` for the information on what `-e` means. Note that in bash, `[` itself is a command. Therefore, `!` is the first arg to it, `-e` is the 2nd arg to it, `"$F"` is the 3rd arg, `]` is the 4th arg. That's why spaces are required after the `[` and before the `]`--the first is the command name and the latter is a required argument, and commands and arguments must always be separated by spaces. – Gabriel Staples Mar 14 '21 at 08:45
38

This should print out links that are broken:

find /target/dir -type l ! -exec test -e {} \; -print

You can also chain in operations to find command, e.g. deleting the broken link:

find /target/dir -type l ! -exec test -e {} \; -exec rm {} \;
Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
  • This doesn't work well if you are actually running lots of code. Do you have a `if` solution ? – Freedo Aug 30 '19 at 17:50
11

this will work if the symlink was pointing to a file or a directory, but now is broken

if [[ -L "$strFile" ]] && [[ ! -a "$strFile" ]];then 
  echo "'$strFile' is a broken symlink"; 
fi
Aquarius Power
  • 3,729
  • 5
  • 32
  • 67
  • wouldn't the `-L "$strFile"` suffice? From the docs: `[-L FILE ] True if FILE exists and is a symbolic link.` ([source](http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html). – Sos Jul 22 '19 at 08:12
  • 1
    @Sosi could this be required in an old bash version? 2014 vs 2019, I could even dont have that version anymore :) – Aquarius Power Jul 22 '19 at 19:08
  • right! that's a great point! I didn't notice how old this was, and now I feel bad for digging it up – Sos Jul 23 '19 at 07:02
  • @Sosi I think there is no problem, an updated app version's answer is always better I guess – Aquarius Power Jul 23 '19 at 17:02
  • 3
    @Sosi We want to test if the symbolic link is working, -L is true even if the file is just a broken symlink – Freedo Aug 30 '19 at 17:51
4

This finds all files of type "link", which also resolves to a type "link". ie. a broken symlink

find /target -type l -xtype l
ACyclic
  • 5,904
  • 6
  • 26
  • 28
2

If you don't mind traversing non-broken dir symlinks, to find all orphaned links:

$ find -L /target -type l | while read -r file; do echo $file is orphaned; done

To find all files that are not orphaned links:

$ find -L /target ! -type l
ACyclic
  • 5,904
  • 6
  • 26
  • 28
William Pursell
  • 204,365
  • 48
  • 270
  • 300
-1

What's wrong with:

file $f | grep 'broken symbolic link'

Rew Brian
  • 23
  • 5
  • 3
    There's a few things wrong with it: 1) it follows a working symbolic link and, if the target is a file, will read the contents to try to determine its type; 2) how the output is worded may not be the same everywhere and forever; 3) if the system it's run on is in a locale other than English, it may not print the English message. Add `-h` flag to fix the first problem, and prefix it with `LANG=C` to fix the third. You may or may not consider the second problem an acceptable risk. – kbolino Jul 10 '19 at 22:33
-1

If it does qualify as a symbolic link, but is „not existing“, its a broken link.

if [[ -h $link && ! -e $link ]] ; then
    _info "$link is a BROKEN SYMLINK"
fi

REFERENCE

Frank N
  • 9,625
  • 4
  • 80
  • 110
  • `-h` is described as *True if file exists and is a symbolic link.* If `-h` is true then `-e` is true. – docwhat Jun 27 '22 at 16:27