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

Tags:

Ls

Wc