set -- 2009*
This sets the list of positional parameters (
$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 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
-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
$ ls -l
-rw-r--r-- 1 kk wheel 0 May 28 11:09 2009?was?a?good?year
$ ls -1
$ ls | wc -l
$ ls -1 | wc -l
$ set -- 2009*
$ echo "$#"
set and outputting
$# additionally does not use any external commands in most shells)
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.
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).
** in (with
shopt -s globstar in
set -o extended-glob in
yash, or in any other shell that may support it), to count recursively:
set -- **/2009*
** matches almost like
*, but also matches across
/ in pathnames.