I have a question concerning linux commands. How do I count all the files that begin with letters from a to g?

  • The file names, or the file contents? In a single directory, in a whole directory tree? – Gilles 'SO- stop being evil' Nov 8 '12 at 23:15
set -- [a-gA-G]*
if [ "$1" = '[a-gA-G]*' ]; then
  echo 0
  echo "$#"
  • 4
    +1 for using shell internal commands only ;o) – jippie Nov 8 '12 at 21:41
  • You of all people might have mentioned zsh: print -lr [A-Ga-g]*(N) (or print -lr (#i)[a-g]*(N) if you want to be fancy). – Gilles 'SO- stop being evil' Nov 8 '12 at 23:18
  • @Gilles, You mean n=0;: (#i)[a-g]*(Ne:'((!++n))':) ? ;-) – Stéphane Chazelas Nov 9 '12 at 6:26
  • @StephaneChazelas Ah, oops, I somehow dropped “count” when I wrote this. (a=((#i)[a-g]*(N)); echo $#a) is less typing (and less cryptic). – Gilles 'SO- stop being evil' Nov 9 '12 at 11:06
  • @Gilles, I was going to say it's less efficient as it sorts the list (which you can disable with newers versions of zsh though) and stores it in memory, but in fact, it appears to be faster because for some reason mine causes zsh to do a lstat(2) on each file – Stéphane Chazelas Nov 9 '12 at 11:53

You can do it with a one-line shell command:

find / -name '[abcedfg]*' -print | wc -l

You will see some messages about how find doesn't have permission to read some directory or another, but you will get a count of files whose names begin with those 7 letters.

  • any reason to specify [abcedfg] vs just [a-g]? – amphibient Nov 8 '12 at 20:37
  • Just a habit for me. Those two shell globs should match the same file names, but I think seeing all the characters in a range is clearer, at least for small numbers of characters. – Bruce Ediger Nov 8 '12 at 21:24
  • 1
    Note that files with newline characters in their path will be counted several times. – Stéphane Chazelas Nov 8 '12 at 21:39
  • 4
    @foampile, the behavior of meaning ranges is locale dependant. [a-g] will match é in most non-ASCII locales contrary to [abcdefg] – Stéphane Chazelas Nov 8 '12 at 21:45

The GNU implementation of the ls command (which you are using since you are running Linux) will find all files in the current directory starting with a character a-g.

ls --ignore='[!a-g]*'

It tells to ignore all files that do not start with a character in the range [a-g]. The ! inverts the filter. * indicat

Next run the output through wc -l to count the lines.

The full command will thus be:

ls --ignore='[!a-g]*' | wc -l

This solution will not recurs into subdirectories.

  • I'm running Linux and my ls is implemented by BusyBox. Maybe you should explain why you're inverting the pattern then ignoring it, rather than just doing ls [a-g]* (I assume in order to handle the case of 0 matches, or the glob expanding into too many arguments.) And as @StephaneChazelas says in a comment to another answer, why not add -d to avoid recursing into directories? – dubiousjim Nov 9 '12 at 17:34
  • @dubiousjim -d wouldn't help here as ls is not given any argument so it defaults to the current directory. With -d, it would just return "." – Stéphane Chazelas Nov 9 '12 at 18:35

GNU find can do that for you:

find ./ -type f -maxdepth 1 -iname "[a-g]*" 2> /dev/null | wc -l

this finds all files (not directories) under ./ but digs into no further directories and matches the name (case insensitive) of the file beginning with "a-g", redirects all errors to /dev/null and then counts the files

ls -1 [a-g]* | wc -l

Why do it like this? Because you probably want the simplest answer; this one assumes you don't have to worry about not counting directories, nor searching sub-directories, nor upper-case filenames... and this is the command I most often use.

  • -1 is not necessary when the output is not to a terminal (like a pipe or socketpair (ksh93) above). What's the harm in adding a -d option and make it correct? – Stéphane Chazelas Nov 9 '12 at 12:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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