3

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

1
  • The file names, or the file contents? In a single directory, in a whole directory tree? Nov 8, 2012 at 23:15

5 Answers 5

7
LC_ALL=C
set -- [a-gA-G]*
if [ "$1" = '[a-gA-G]*' ]; then
  echo 0
else
  echo "$#"
fi          
5
  • 4
    +1 for using shell internal commands only ;o)
    – jippie
    Nov 8, 2012 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). Nov 8, 2012 at 23:18
  • @Gilles, You mean n=0;: (#i)[a-g]*(Ne:'((!++n))':) ? ;-) Nov 9, 2012 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). Nov 9, 2012 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 Nov 9, 2012 at 11:53
4

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.

4
  • any reason to specify [abcedfg] vs just [a-g]?
    – amphibient
    Nov 8, 2012 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.
    – user732
    Nov 8, 2012 at 21:24
  • 1
    Note that files with newline characters in their path will be counted several times. Nov 8, 2012 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] Nov 8, 2012 at 21:45
3

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.

2
  • 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, 2012 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 "." Nov 9, 2012 at 18:35
2

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

0
1
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
  • -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? Nov 9, 2012 at 12:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .