count number of files in directory with a certain name
set -- 2009*
echo "$#"
This sets the list of positional parameters ($1
, $2
, ..., etc.) to the names matching 2009*
. The length of this list is $#
.
The issue with ls -1 | wc -l 2009*
is that you execute wc -l
directly on the files matching 2009*
, counting the number of lines in each. Meanwhile, ls -1
is trying to write to the standard input of wc
, which wc
is not reading from since it was given an explicit list of files to work on.
You may have wanted to use ls -d 2009* | wc -l
. This would have listed all the names that match 2009*
(using ls
with -d
to not list the contents of directories), and would count the number of lines in the output. Note that -1
is not needed if you pipe the result of ls
somewhere (unless ls
is an alias or shell function that forces column output).
Note also that this would give you the wrong count if any filename contains a newline:
$ touch '2009
> was
> a
> good
> year'
$ ls
2009?was?a?good?year
$ ls -l
total 0
-rw-r--r-- 1 kk wheel 0 May 28 11:09 2009?was?a?good?year
$ ls -1
2009?was?a?good?year
$ ls | wc -l
5
$ ls -1 | wc -l
5
However:
$ set -- 2009*
$ echo "$#"
1
(using set
and outputting $#
additionally does not use any external commands in most shells)
Using find
to count recursively:
find . -type f -name '2009*' -exec echo . \; | wc -l
Here, we output a dot for each found pathname in or under the current directory, and then we count the number of lines that this produces. We don't count the filename strings themselves, and instead do it this way to avoid counting too many lines if a filename contains newlines.
With find
we're able to more closely control the type of file that we count. Above, we explicitly test for regular files with -type f
(i.e. not directories and other types of files). The *
pattern in the shell does not distinguish between directories and files, but the zsh
shell can use *(.)
to modify the behaviour of the pattern to only match regular files (the zsh
user would probably use 2009*(.)
instead of 2009*
in the non-find
variations above and below).
Using **
in (with shopt -s globstar
in bash
, or set -o extended-glob
in yash
, or in any other shell that may support it), to count recursively:
set -- **/2009*
echo "$#"
The pattern **
matches almost like *
, but also matches across /
in pathnames.
Tried with below command and it worked fine and got the result
find . -maxdepth 1 -type f -iname "2009*" | awk '{print NR}'| sed -n '$p'
Note: If you want to under subdirectory also Kindly remove maxdepth option