Sure, you can use a loop, but why would you use a loop when you don't need one?
The shell has all the tools to enumerate the files in a directory and to count them. The basic idea (packaged in a function) is
count_files () {
set *
echo $#
}
i.e. set the positional arguments to the list of names of files in the current directory and print the number of positional arguments. This breaks down in several edge cases:
- If the first file name starts with
-
, it's interpreted as an option to set
. Easily solved with set -- *
.
- If there are no matching files, the
*
is left unchanged. If you want to be portable to POSIX shells, you need to handle this special case. If you can afford to require ksh, bash or zsh, they have better ways.
- This excludes dot files (files beginning with a
.
). They need to be included separately. The glob .*
lists dot files, including .
and ..
except in pdksh and all other descendants of the Forsyth shell and zsh (and bash
if GLOBIGNORE
is not empty). Assuming that those should not be counted, just subtract 2.
POSIX solution:
count_files () {
set -- * .*
if [ "$1" = "*" ] && ! [ -e "$1" ] && ! [ -L "$1" ]; then
shift # Remove the * which didn't match any file
fi
echo $#
}
Ksh93 solution:
function count_files {
typeset FIGNORE='@(.|..)'
set -- ~(N)
echo $#
}
Bash solution:
count_files () (
shopt -s dotglob nullglob
set -- *
echo $#
)
Zsh solution:
count_files () {
emulate -LR zsh
set -- *(DN)
echo $#
}
\n
.