How to count number of files in each directory?

I am able to list all the directories by

find ./ -type d

I attempted to list the contents of each directory and count the number of files in each directory by using the following command

find ./ -type d | xargs ls -l | wc -l

But this summed the total number of lines returned by

find ./ -type d | xargs ls -l

Is there a way I can count the number of files in each directory?


Solution 1:

This prints the file count per directory for the current directory level:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr

Solution 2:

Assuming you have GNU find, let it find the directories and let bash do the rest:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done

Solution 3:

find . -type f | cut -d/ -f2 | sort | uniq -c
  • find . -type f to find all items of the type file, in current folder and subfolders
  • cut -d/ -f2 to cut out their specific folder
  • sort to sort the list of foldernames
  • uniq -c to return the number of times each foldername has been counted

Solution 4:

You could arrange to find all the files, remove the file names, leaving you a line containing just the directory name for each file, and then count the number of times each directory appears:

find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c

The only gotcha in this is if you have any file names or directory names containing a newline character, which is fairly unlikely. If you really have to worry about newlines in file names or directory names, I suggest you find them, and fix them so they don't contain newlines (and quietly persuade the guilty party of the error of their ways).


If you're interested in the count of the files in each sub-directory of the current directory, counting any files in any sub-directories along with the files in the immediate sub-directory, then I'd adapt the sed command to print only the top-level directory:

find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c

The first pattern captures the start of the name, the dot, the slash, the name up to the next slash and the slash, and replaces the line with just the first part, so:

./dir1/dir2/file1

is replaced by

./dir1/

The second replace captures the files directly in the current directory; they don't have a slash at the end, and those are replace by ./. The sort and count then works on just the number of names.