There is no need for ls
, sed
, wc
or awk
.
If you simply want to count how many names a pattern expands to, then you can do that with
set -- *
echo "$#"
The set
command sets the positional parameters ($1
, $2
, etc.) to the names matching the *
pattern. This automatically sets the special variable $#
to the number of set positional parameters, i.e. the number of names matching the given pattern.
In bash
or in a shell that has named arrays, you can use
names=(*)
echo "${#names[@]}"
This works similarly, but sets the elements of the names
array to the names resulting from the expansion of the *
pattern. The variable expansion ${#names[@]}
will be the number of elements in the names
array.
An issue with this is that if the pattern doesn't match anything, it will remain unexpanded, so you get a count of 1 (even though the directory is empty). To fix this in the bash
shell, set the nullglob
shell option with shopt -s nullglob
. By setting this shell option, patterns that do not match anything will be removed completely.
In bash
, if you additionally want to count hidden names, set the dotglob
shell option with shopt -s dotglob
.
Your function could look something like this in bash
:
lsc () (
shopt -s nullglob
set -- "$1"/*
echo "$#"
)
Note the use of ( ... )
for the function body to avoid setting nullglob
in the calling shell.
Or, for /bin/sh
:
lsc () {
set -- "$1"/*
if [ -e "$1" ] || [ -L "$1" ]; then
echo "$#"
else
echo 0
fi
}
The if
statement here makes sure that the first positional parameter is the name of an actual file and not an unexpanded pattern (due to not matching anything). The -e
("exists") must be true for us to trust the number in $#
. If it isn't true, then we additionally check whether the name refers to a symbolic link with the -L
test. If this is true, we know that the first thing that the pattern expanded to was a "dead" symbolic link (a symbolic link pointing to a non-existent file), and we trust $#
to be correct. If both tests fail, we know that we didn't match anything and therefore output 0
.
ls -1 | wc -l
(that's a number 1 rather than a letter l) ? Or if keen on usingawk
, you could usels -l | awk 'NR>1{a++}END{print a}'
logrotate
tried to handle such a file. Not writing your code to account for all possible file name characters is just asking for trouble./
because directory paths are/
-separated. There's simply no reason to disallow any other characters, people just have to write their code correctly and, as @kusalananda mentioned, it's easy to do so.