I have a question concerning linux commands. How do I count all the files that begin with letters from a to g?
5 Answers
LC_ALL=C
set -- [a-gA-G]*
if [ "$1" = '[a-gA-G]*' ]; then
echo 0
else
echo "$#"
fi
-
4
-
You of all people might have mentioned zsh:
print -lr [A-Ga-g]*(N)
(orprint -lr (#i)[a-g]*(N)
if you want to be fancy). Nov 8, 2012 at 23:18 -
-
@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
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.
-
-
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.– user732Nov 8, 2012 at 21:24
-
1Note 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
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 doingls [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? 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
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? Nov 9, 2012 at 12:17