$(find -maxdepth 1 -type d)
outputs the list of directories in the current directory. Unless there are directories whose name begins with a .
, this is a complex way of writing */
. It's also unreliable: it only works if none of the directory names contain whitespace or globbing characters \[?*
. That's because the result of the command substitution $(…)
is split into separate words wherever there's a whitespace character, and each word is interpreted as a glob (filename wildcard pattern). You can avoid this behavior by putting the command substitution in double quotes ("$()"
), but then the list that the loop iterates on will contain a single element which is the concatenation of the directory names separated by newlines.
Note this shell programming rule: always put double quotes around variable substitutions and command substitutions ("$foo"
, "$(foo)"
) unless you know that you need to leave the double quotes out and you understand how it's safe to leave them out.
The other problem with your script is a simple one: echo find "$dir"
always prints out one line; you meant find "$dir"
.
for dir in */; do
echo "$dir"
find "$dir" | wc -l
done
Note that this only works if no file inside that tree contains newlines. If they might, you can make the find
command print something reliable. With GNU find (i.e. on non-embedded Linux or Cygwin):
for dir in */; do
echo "$dir"
find "$dir" -printf a | wc -c
done
Portably:
for dir in */; do
echo "$dir"
find "$dir" -exec printf %c {} + | wc -c
done
-printf x
: otherwise, the default will output the name of the file (which could : contain "newline", and therefore be counted twice. Or contain other things such as "NULL" characters, making lots of commands choke) – Olivier Dulac Apr 03 '13 at 11:35