After researching and testing i've got
find . -maxdepth 1 -type d -print0 | sort -z | \
while IFS= read -r -d '' i ; do \
echo -n "$i: " ; (find "$i" -type f | wc -l) ; done
Explanation
-maxdepth 1
- I need only one level of recursion
-type d
- only directories
-print0 | while IFS= read -r -d '' i
- I have spaces in directories. The -r
option to read
prevents backslash interpretation (usually used as a backslash newline pair, to continue over multiple lines or to escape the delimiters). Without this option, any unescaped backslashes in the input will be discarded. You should almost always use the -r
option with read
.
The most common exception to this rule is when -e
is used, which uses Readline
to obtain the line from an interactive shell. In that case, tab completion will add backslashes to escape spaces and such, and you do not want them to be literally included in the variable. This would never be used when reading anything line-by-line, though, and -r
should always be used when doing so.
By default, read
modifies each line read, by removing all leading and trailing whitespace characters (spaces and tabs, if present in IFS
). If that is not desired, the IFS
variable may be cleared, as in the example above.
The IFS variable is used in shells (Bourne, POSIX, ksh, bash) as the input field separator (or internal field separator). Essentially, it is a string of special characters which are to be treated as delimiters between words/fields when splitting a line of input.
The default value of IFS
is space, tab, newline. (A three-character string.) If IFS
is unset, it acts as though it were set to this default value. (This is presumably for simplicity in shells that do not support the $'...' syntax for special characters.) If IFS
is set to an empty string (which is very different from unsetting it!) then no splitting will be performed.
In the read command, if multiple variable-name arguments are specified, IFS
is used to split the line of input so that each variable gets a single field of the input. (The last variable gets all the remaining fields, if there are more fields than variables.)
sort -z
- sort output of find in alfabetical order
do echo -n "$i: "
- print directory name and colon
find "$i" -type f
- find files only inside each directory
wc -l
- display number of files (lines of second find
output)
Example
~/tmp$ tree
.
├── 1000
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
│ ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
│ ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ └── original_thumb.jpg
├── 10000
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10001
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10005
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10006
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10009
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 1001
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
│ ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
│ └── original_thumb.jpg
├── 10011
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10015
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10016
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ ├── 640x320_cropped_d4dcbfaafb98dafcbc594b020ce7c54b.jpg
│ └── original_thumb.jpg
├── 10017
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10018
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10019
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ ├── 640x320_cropped_d4dcbfaafb98dafcbc594b020ce7c54b.jpg
│ └── original_thumb.jpg
├── 1002
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
│ ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
│ ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ └── original_thumb.jpg
├── 10021
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10025
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 640x320_cropped_6450e078c12f532b29ba57eeb58ca8b3.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10028
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
├── 10029
│ ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│ ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│ ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│ └── original_thumb.jpg
└── 1003
├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
└── original_thumb.jpg
19 directories, 89 files
Using explained above one-liner:
~/tmp$ find . -maxdepth 1 -type d -print0 | sort -z | \
> while IFS= read -r -d '' i ; do \
> echo -n "$i: " ; (find "$i" -type f | wc -l) ; done
.: 89
./1000: 5
./10000: 5
./10001: 4
./10005: 4
./10006: 5
./10009: 5
./1001: 4
./10011: 5
./10015: 4
./10016: 5
./10017: 4
./10018: 4
./10019: 5
./1002: 5
./10021: 5
./10025: 6
./10028: 4
./10029: 5
./1003: 5