If you just want something that works on (GNU) Linux:
find -type l -xtype d -print
This has the advantage that you can specify some action other than -print
.
If you need POSIX then perhaps something like this:
(
export LC_COLLATE=C
find . -type l -print | sort > ListOfLinks &
find -L . -type d -print | sort > ListOfDirs &
wait
comm -12 ListOfLinks ListOfDirs
)
(Refer to the POSIX specs for find, sort, and comm.)
Note that this will traverse directories pointed to by symlinks that it finds, so in some cases it will perform worse than your naïve version.
This outputs one path per line, with the usual caveat: it can't work if you have newlines in your filenames, so if you need to handle filenames with newlines, you'll need to pick some different tools -- see GNUish method above, or try something like ...
If you have Perl you could write:
perl -Mv5.10 -MFile::Find -e '
find( { wanted => sub { -l && -d && say },
no_chdir => 1 }, @ARGV )
' .
(Don't forget the .
on the end; that's the current directory. Corresponding answers using Python and other languages are left as exercises for the reader; the key point is there's a call-back function that's invoked for each name.)
ls -l | grep '^l'
is wrong, it'll fail for files containing^l
or new lines Why not parsels
(and what to do instead)?, https://mywiki.wooledge.org/ParsingLs – phuclv Oct 19 '23 at 11:37ls
, but that's not one of them.grep '^l'
will never match a circumflex followed by a lower-case ell. You'd have to usegrep '\^l'
orgrep -F '^l'
. – Jim L. Nov 15 '23 at 16:14