Qual é a melhor maneira de contar os resultados “encontrados”?

97

Minha solução atual seria find <expr> -exec printf '.' \; | wc -c, mas isso leva muito tempo quando há mais de 10.000 resultados. Não há maneira mais rápida / melhor de fazer isso?

MechMK1
fonte
use wc -l para encontrar resultados
Manuel Selva

Respostas:

82

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)

Gilles Quenot
fonte
6
Não equivalente, é mais confiável =)
Gilles Quenot
6
Não é mais confiável se o sinalizador -printf para localizar não for compatível com sua plataforma. ;-)
Randy Howard
7
Observe que você pode economizar alguns nanossegundos a mais não citando o ponto-printf '.'
Jens
6
@Jens - especialmente quando você leva em consideração o tempo necessário para digitar isso
Brian Agnew
6
Com um benchmark tão pequeno, os tempos são provavelmente dominados por outros fatores além do que você deseja medir. Um experimento com uma grande árvore seria mais útil. Mas isso recebe meu voto para realmente fazer o que o OP pediu.
tripleee
132

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.

Brian Agnew
fonte
9
-1: irá quebrar no arquivo com novas linhas, e é mais lento do que contar bytes =)
Gilles Quenot
21
Eu não acho que justifique uma votação negativa, visto que a limitação de nome de arquivo / nova linha é muito rara e mencionada acima. Mais devagar ? Possivelmente. Dado que você está consultando um sistema de arquivos, suspeito que a diferença de velocidade seja pequena. Em todos os meus 10.000 arquivos, medi uma diferença de 3 ms
Brian Agnew,
8
A diferença de desempenho entre 'find <expr> | wc -l' e 'find <expr> -printf. | wc -c 'são extremamente pequenos. O armazenamento em cache (ou seja, se você executar o mesmo find duas vezes na mesma árvore) é muito mais importante. IMHO a solução com "wc -l" é muito mais intuitiva.
pitseeker
4

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.

John B
fonte
3

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'
carlo
fonte