Respostas:
Tente isto em vez (require find's -printfsuporte):
find <expr> -type f -printf '.' | wc -c
Será mais confiável e rápido do que contar as linhas.
Observe que eu uso o find's printf, não um comando externo.
Vamos sentar um pouco:
$ ls -1
a
e
l
ll.sh
r
t
y
z
Meu snippet de referência:
$ time find -type f -printf '.' | wc -c
8
real 0m0.004s
user 0m0.000s
sys 0m0.007s
Com linhas completas:
$ time find -type f | wc -l
8
real 0m0.006s
user 0m0.003s
sys 0m0.000s
Então minha solução é mais rápida =) (a parte importante é a reallinha)
-printf '.'
Por que não
find <expr> | wc -l
como uma solução portátil simples? Sua solução original é gerar um novo processo printf para cada arquivo individual encontrado, e isso é muito caro (como você acabou de descobrir).
Observe que isso será superestimado se você tiver nomes de arquivo com novas linhas incorporadas, mas se você tiver isso, suspeito que seus problemas sejam um pouco mais profundos.
Esta solução é certamente mais lenta do que algumas das outras find -> wcsoluções aqui, mas se você estivesse inclinado a fazer outra coisa com os nomes dos arquivos além de contá-los, você poderia a readpartir da findsaída.
n=0
while read -r -d ''; do
((n++)) # count
# maybe perform another act on file
done < <(find <expr> -print0)
echo $n
É apenas uma modificação de uma solução encontrada no BashGuide que lida adequadamente com arquivos com nomes fora do padrão, tornando o finddelimitador de saída um byte NUL usando print0e lendo a partir dele usando ''(byte NUL) como o delimitador de loop.
Esta é minha countfilesfunção no meu ~/.bashrc(é razoavelmente rápida, deve funcionar para Linux e FreeBSD finde não se deixa enganar por caminhos de arquivo contendo caracteres de nova linha; o final wcapenas conta bytes NUL):
countfiles ()
{
command find "${1:-.}" -type f -name "${2:-*}" -print0 |
command tr -dc '\0' | command wc -c;
return 0
}
countfiles
countfiles ~ '*.txt'