On windows I have a program that can count all the files on a hard drive and the output shows a list of file extensions and a number (which showed how many files on the drive were for example are jpg).

How do I do this in a terminal on gnu+linux?

find /filesystem -xdev -type f -name '?*.*' -print0 | awk -F. -vRS='\0' '
   {c[$NF]++}; END{for (i in c) print c[i],i}' | sort -rn | less

Where /filesytem is the mount point of the file system you want to look into.

  • what's up with all of these community wiki answers lately? You just can't be bothered to explain them maybe? – mikeserv Sep 1 '14 at 21:41

The unix philosophy is to provide the building blocks, and let you assemble those building blocks to perform specialized tasks such as this one.

The find command traverses a directory tree and lists files matching certain criteria or acts on them. For example, find -xdev / traverses all files on the root filesystem and displays their name. The option -xdev omits files on other filesystems, such as network mounts, special filesystems that provide system information, etc.

To choose what is printed, GNU find offers the -printf action. The %f directive prints file names without a directory part.

Linux file names can contain any byte except slashes (which are directory separators) and null bytes. If you're willing to assume that your file names don't contain newline characters, the processing of file names will be simpler. For safety, you can exclude file names that contain a newline.

find / -xdev ! -name $'*\n*' -printf '%f\n'

To select files that have an extension, we'll match a name containing a dot that isn't the first character, and only regular files (you may or may not want to include symbolic links as well).

find / -xdev -name '?*.*' ! -name $'*\n*' -type f -printf '%f\n'

Enough with find. To work on the extensions, we'll use text processing tools, using a shell pipeline to combine them. First sed to do a bit of rewriting to eliminate the part of the file name that isn't the extension:

find / -xdev -name '?*.*' ! -name $'*\n*' -type f -printf '%f\n' |
  sed 's/.*\.//'

And finally, to count the number of occurrences of each extension, we sort the output and count duplicates, and finally sort the result by number of occurrences.

find / -xdev -name '?*.*' ! -name $'*\n*' -type f -printf '%f\n' |
  sed 's/.*\.//' | sort | uniq -c | sort -n
  • I was really surprised by the number of .png files a system can have! – user44370 Aug 26 '14 at 2:48
  • Note that sort | uniq -c doesn't count duplicates, but the number of occurrences of lines that sort the same in the current locale. For instance, for me a.②, b.③ c.① show up as 3 files because , and sort the same in my locale. You can fix the locale to C for sort and uniq -c with LC_ALL=C sort | LC_ALL=C uniq -c to really count duplicates. – Stéphane Chazelas Aug 26 '14 at 5:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.