That ugly solution above really bugged me. I now have a better solution, but decided to post it separately. The lesson I learned is, that even programs like 'comm', which take two files as parameters may be "fed" from stdin. Since comm does precisely the job you asked for -- namely computing the difference or intersection of two sequences of text -- it is then straightforward to write the script.
Enough talk, here is the code
Code:
#!/bin/bash
links=$( find . -maxdepth 1 -type l -printf '%f ' )
targets=
for l in ${links}; do
targets="${targets} $(readlink ${l})"
done
non_slinks=$( comm -23 <( find . -maxdepth 1 -type d -printf '%f\n' | sort) <( echo "${targets}" | sed -e 's/ /\n/g' | sort ) )
echo -e "\nAll directories that are neither source or target of symlink:"
echo ${non_slinks}
The command 'comm -23 FILE1 FILE2' reads two sorted files FILE1 and FILE2 and returns all the lines of FILE1 that do not occur in FILE2. In our case, FILE1 is a list of directories and FILE2 is a list of all the targets of symlinks. The targets of symlinks are build with 'readlink' and your original 'find -type l' solution. The 'sed s/ /\n/g' hack is "necessary" to separate the entries in the ${target} variable. Finally note that
does not return any symlinks by default. The manual page says that symlinks are a separate filetype.
Altogether, the only thing left from my first attempt, is using 'readlink' to determine the targets of symlinks. I hope this helps. I tested this script and it seemed to work. This solution is also way faster than my first attempt.
EDIT: There was a bug in my first second attempt. I really hope that this works now.