Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to show this kind of statistics about a particular directory:

$ myscript.sh
.c 34265 files
.h 17866 files
.cbl 1804 files
.pco 389 files

Is there a tool that can do this?

Here is my attempt:

find . -name "*.*" | sed -e "s/.*\.//g" | sort -u

And then I could type for each type find . -name "*.pc" | wc -l but it is bothersome so I wrote:

find . -name "*.*" | sed -e "s/.*\.//g" | sort -u |\
    xargs find . -name "*.{}" | wc -l

Unfortunately I must be missing something because it says:

find: paths must precede expression: as

("as" is the first extension)
Any idea what is going wrong?
Is there already a tool that does what I want (a tool counting file lines would be OK too).

share|improve this question
up vote 1 down vote accepted

It can be done with gawk: pipe your list of filenames through the following (left as an exercise/I tested with ls -1, but Don't Parse ls(tm)):

gawk -F. '1 {exts[$NF]++} END {for (ext in exts){printf "%s: %s files\n", ext, exts[ext]}}'

This assumes that everything that is followed by a period is not part of the extension, so filenames without period count as all-extension. (I think it should be sufficient to change 1 { to (NF>1) { to only get files with extensions proper.

share|improve this answer
That works! Here is the complete command: find . -name "*.*" | gawk -F. '(NF>1) {exts[$NF]++} END {for (ext in exts){printf "%s: %s files\n", ext, exts[ext]}}' – Nicolas Raoul Feb 17 '12 at 7:26

The following pipeline prints each distinct line in the input preceded by its repeat count, sorted by decreasing repeat count:

sort | uniq -c | sort -rn


find . -type f -name '?*.*' | sed 's/.*\.//' | sort | uniq -c | sort -rn
share|improve this answer
ls -1 | awk -F. '{if(NF>1)arr[$NF]++;else blnk++}END{for(i in arr)printf(".%s %s file(s)\n",i,arr[i]);printf("<No Extension> %s file(s)\n",blnk)}'
share|improve this answer
Using ls is typically not a good idea (ie. it is a bad idea). eg. it prints a line in which the link's target's extension is returned. So the awk filter reports on the wrong extension.. It will also pick up directory names which have a dot in their names.. Aside from the mentioned and other complications caused by ls, I like the awk logic.. (and it appears that he wants the output sorted by the number of occurrences) – Peter.O Feb 17 '12 at 10:34

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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