To find the number of names in a single directory, expand the * glob in it and count the number of generated words:
shopt -s nullglob # to make the * glob expand to nothing
# if there is no matching names
set -- *
num=$#
printf '%s\n' "$num"
The special value $# is the number of positional parameters. The set command sets the positional parameters.
Would you want to count regular files only, and include hidden names, then use
shopt -s nullglob dotglob
for name in *; do
if [ ! -f "$name" ] || [ -L "$name" ]; then
# skip non-regular files and symbolic links
continue
fi
files+=( "$name" )
done
num=${#files[@]}
printf '%s\n' "$num"
To do that recursively into subdirectories, also set the globstar shell option and use **/* as the globbing pattern.
(in the zsh shell, it would be enough with set -- **/*(.DN); print $#)
The issue with your
num=$(( ls | wc -l ))
is twofold:
$(( ... )) is an arithmetic expansion. You probably want a command substitution here, $( ... ).
- The
wc -l will not count files. It will count the number of newline characters outputted by ls. A file with one or more newlines in its name will be counted as multiple files by wc -l. You can test this by creating such a file using touch $'hello\nworld'.