Optimized solutions for GNU find†
At least for some system+filesystem combinations, find doesn't need to stat a file to get its type. Then you can check if it's a directory before testing readability to speed up the search‡ —I've got some 30% improvement in tests I did. So for long searches or searches that run often enough, use one of these:
Print everything visible
$ find . -print -type d ! -readable -prune
$ find . -type d ! -readable -prune , [expression] -print
Print visible files
$ find . -type d \( ! -readable -prune -o -true \) -o [expression] -print
Print visible directories
$ find . -type d -print ! -readable -prune
$ find . -type d \( ! -readable -prune , [expression] -print \)
Print only readable directories
$ find . -type d ! -readable -prune -o [expression] -print
Notes
† The -readable and , (comma) operators are GNU extensions. This expression
$ find . [expression] , [expression]
is logically equivalent to
$ find . \( [expression] -o -true \) [expression]
‡ This is because find implementations with this optimization enabled will avoid stating non-directory files at all in the discussed use case.
Edit: shell function
Here is a POSIX shell function I ended up with to prepend this test to any expression. It seems to work fine with the implicit -print and command-line options:
findr () {
j=$#; done=
while [ $j -gt 0 ]; do
j=$(($j - 1))
arg="$1"; shift
test "$done" || case "$arg" in
-[A-Z]*) ;; # skip options
-*|\(|!) # find start of expression
set -- "$@" \( -type d ! -readable -prune -o -true \)
done=true
;;
esac
set -- "$@" "$arg"
done
find "$@"
}
The other two alternatives listed in the answers caused either a syntax error in POSIX shell (couldn't even source a file containing the function definition) or bad output in ZSH... Running time seems to be equivalent.