du which counts number of files/directories rather than size

I am trying to clean up a hard drive which has all kinds of crap on it accumulated over the years. du has helped reduce disk usage, but the whole thing is still unwieldily not due to the total size, but due to the sheer number of files and directories in total.

Is there a way I can do something like du but not counting file size, but rather number of files and directories? For example: a file is 1, and a directory is the recursive number of files/directories inside it + 1.

Edit: I should have been more clear. I'd like to not only know the total number of files/directories in /, but also in /home, /usr etc, and in their subdirectories, recursively, like du does for size.


I have found du --inodes useful, but I'm not sure which version of du it requires. On Ubuntu 17.10, the following works:

du --inodes      # all files and subdirectories
du --inodes -s   # summary
du --inodes -d 2 # depth 2 at most

Combine with | sort -nr to sort descending by number of containing inodes.


The easiest way seems to be find /path/to/search -ls | wc -l

Find is used to walk though all files and folders.
-ls to list (print) all the names. This is a default and if you leave it out it will still work the same almost all systems. (Almost, since some might have different defaults). It is a good habit to explicitly use this though.

If you just use the find /path/to/search -ls part it will print all the files and directories to your screen.


wc is word count. the -l option tells it to count the number of lines.

You can use it in several ways, e.g.

  • wc testfile
  • cat testfile | wc

The first option lets wc open a file and count the number of lines, words and chars in that file. The second option does the same but without filename it reads from stdin.


You can combime commands with a pipe |. Output from the first command will be piped to the input of the second command. Thus find /path/to/search -ls | wc -l uses find to list all files and directory and feeds the output to wc. Wc then counts the number of lines.

(An other alternative would have been `ls | wc', but find is much more flexible and a good tool to learn.)


[Edit after comment]

It might be useful to combine the find and the exec.

E.g. find / -type d ! \( -path proc -o -path dev -o -path .snap \) -maxdepth 1 -exec echo starting a find to count to files in in {} \; will list all directories in /, bar some which you do not want to search. We can trigger the previous command on each of them, yielding a sum of files per folder in /.

However:

  1. This uses the GNU specific extension -maxdepth.
    It will work on Linux, but not on just any unix-a-alike.
  2. I suspect you might actually want a number fo files for each and every subdir.

The following PHP script does the trick.

#!/usr/bin/php
<?php 

function do_scan($dir, $dev) {
  $total = 1;

  if (\filetype($dir) === 'dir' && \lstat($dir)['dev'] == $dev) {
    foreach (\scandir($dir) as $file) {
      if ($file !== '.' && $file !== '..') {
        $total += do_scan($dir . \DIRECTORY_SEPARATOR . $file, $dev);
      }
    }

    print "$total\t$dir\n";
  }

  return $total;
};

foreach (\array_slice($argv, 1) as $arg) {
  do_scan($arg, \lstat($arg)['dev']);
}

Put that in a file (say, "treesize"), chmod +x it and run it with ./treesize . | sort -rn | less.