Se você souber que o diretório atual contém pelo menos um arquivo não oculto:
set -- *; echo "$#"
Isso é obviamente generalizável para qualquer glob.
Em um script, isso tem o efeito colateral às vezes infeliz de substituir os parâmetros posicionais. Você pode contornar isso usando um subshell ou com uma função (versão Bourne / POSIX) como:
count_words () {
eval 'shift; '"$1"'=$#'
}
count_words number_of_files *
echo "There are $number_of_files non-dot files in the current directory"
Uma solução alternativa é $(ls -d -- * | wc -l). Se a glob estiver *, o comando pode ser abreviado para $(ls | wc -l). Analisar a saída de lssempre me deixa desconfortável, mas aqui deve funcionar, desde que os nomes dos seus arquivos não contenham novas linhas ou que você os lsescape. E $(ls -d -- * 2>/dev/null | wc -l)tem a vantagem de lidar com o caso de um globo sem correspondência normalmente (ou seja, ele retorna 0 nesse caso, enquanto o set *método exige testes minuciosos se o globo estiver vazio).
Se os nomes dos arquivos puderem conter caracteres de nova linha, uma alternativa é usar $(ls -d ./* | grep -c /).
Qualquer uma dessas soluções que dependem de passar a expansão de uma glob lspode falhar com um erro muito longo da lista de argumentos se houver muitos arquivos correspondentes.