Existe algo mais rápido do que `encontrar. | wc -l` para contar arquivos em um diretório?

8

Não incomum, eu tenho que contar o número de arquivos em um diretório, às vezes isso chega a milhões.

Existe uma maneira melhor do que apenas enumerá-las e contá-las find . | wc -l? Existe algum tipo de chamada do sistema de arquivos que você pode fazer no ext3 / 4 que consome menos E / S?

MattPark
fonte
3
Você está contando não apenas arquivos, mas diretórios também. Se você deseja apenas contar arquivos, use "find. -Type f | wc -l" se quiser contar links simbólicos e arquivos regulares, use "find. -Type f -ou -type l | wc -l"
FSMaxB
Um diretório é um tipo de arquivo, assim como dispositivos, links simbólicos e soquetes. Arquivos regulares são um subconjunto de arquivos.
precisa
11
O exemplo que você dá sugere que você deseja uma contagem recursiva - se não, então precisa find -maxdepth 1. Observe que, com sua abordagem atual, você contará duas vezes qualquer nome que contenha um caractere de nova linha.
21817 Toby Speight

Respostas:

13

Não é uma aceleração fundamental, mas pelo menos algo :)

find . -printf \\n | wc -l

Você realmente não precisa passar a lista de nomes de arquivos, apenas as novas linhas são suficientes. Essa variante é cerca de 15% mais rápida no meu Ubuntu 12.04.3 quando os diretórios são armazenados em cache na RAM. Além disso, essa variante funcionará corretamente com nomes de arquivos contendo novas linhas.

Curiosamente, essa variante parece ser um pouco mais lenta que a acima:

find . -printf x | wc -c

Caso especial - mas muito rápido

Se o diretório estiver em seu próprio sistema de arquivos, você pode simplesmente contar os inodes:

df -i .

Se o número de diretórios e arquivos em outros diretórios que não o contado não mudar muito, basta subtrair esse número conhecido do df -iresultado atual . Dessa forma, você poderá contar os arquivos e diretórios muito rapidamente.

pabouk
fonte
"Essa variante é cerca de 15% mais rápida ..." me faz pensar se há algum tipo de truque útil que você está usando para cronometrar isso?
Brian Z
4
@BrianZ: Você pode cronometrar um comando acrescentando-o com o tempo. time find /usr/src/ -printf \\n | wc -l, você pode limpar os caches entre as execuções comsudo sync && sudo sysctl -w vm.drop_caches=3
MattPark 17/13/13
Então, eu vi um aumento consistente de 2% na velocidade com uma das 2 primeiras opções sem armazenamento em cache. Então, sim, essa é uma maneira bem legal de fazer isso. Contar os inodes é definitivamente o melhor se o seu ambiente estiver configurado para isso. Eu não tinha considerado.
MattPark
É -printf xpara ser o mesmo que -printf '\0'? Não o vejo mencionado nos documentos.
precisa saber é o seguinte
@CMCDragonkai: A ação -printffunciona de maneira semelhante à printf()função em C, com a principal diferença de que as %diretivas têm um significado diferente. A ação é invocada para cada arquivo encontrado. Isso significa que -printf ximprimirá o caractere xpara cada arquivo encontrado (tente!) E -printf '\0'imprimirá o caractere NULL (código ASCII 0) para cada arquivo encontrado. -printf '\0'não tem significado especial. Ambos funcionarão da mesma forma no exemplo com wc -cnesta resposta.
Pabouk # 5/18
3

Eu escrevi ffcnt exatamente para esse fim. Ele recupera o deslocamento físico dos próprios diretórios com o fiemapioctl e, em seguida, agende a passagem do diretório em várias passagens sequenciais para reduzir o acesso aleatório. A obtenção de uma aceleração comparada com a find | wc depende de vários fatores:

  • tipo de sistema de arquivos: sistemas de arquivos como o ext4, que suportam o fiemapioctl, serão os mais beneficiados
  • velocidade de acesso aleatório: os HDDs beneficiam muito mais do que os SSDs
  • layout do diretório: quanto maior o número de diretórios aninhados, maior o potencial de otimização

(re) montar com relatimeou até nodiratimetambém pode melhorar a velocidade (para todos os métodos) quando os acessos causariam atualizações de metadados.

the8472
fonte
Essa última frase é uma dica que vale a pena! Eu acho que o link para o seu programa seria melhorado se você adicionasse um resumo de como ele funciona. Preferimos respostas completas em si mesmas, caso algo ruim aconteça com o recurso vinculado (mas mantenha o link também, é claro).
precisa
2

Na verdade, no meu sistema (Arch Linux) esse comando

   ls -A | wc -l

é mais rápido que todos os itens acima:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

   real    0m0.007s
   user    0m0.000s
   sys     0m0.004s
MariusMatutiae
fonte
No entanto, acho que o problema com ls é que ele geralmente retorna algo como /bin/ls: Argument list too longse você usar globbing, mas, novamente, pode operar recursivamente como o find também, então talvez seja algo a considerar, não use o find se não for necessário.
MattPark
Parece tão tarde (muitos anos) para comentar sobre isso, mas ls -Aliste apenas os arquivos no diretório atual enquanto findsem -maxdepth 1argumento fará uma pesquisa recursiva em todos os subdiretórios.
Luciano