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.
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
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.
Aug 26, 2014 at 5:47