estatísticas recursivas sobre os tipos de arquivo no diretório?

65

Criei um site para um projeto de conversão. Eu gostaria de fazer algumas estatísticas sobre os tipos de arquivos existentes - por exemplo, 400 .htmlarquivos, 100 .gif, etc. Qual é a maneira mais fácil de fazer isso? Tem que ser recursivo.

Edit: Com o script que maxschelpzig postou, estou tendo alguns problemas devido à arquitetura do site que raspei. Alguns dos arquivos têm o nome *.php?blah=blah&foo=barcom vários argumentos, portanto, todos são considerados únicos. Portanto, a solução precisa *.php*ser do mesmo tipo, por assim dizer.

user394
fonte

Respostas:

96

Você pode usar finde uniqpara isso, por exemplo:

$ find . -type f | sed 's/.*\.//' | sort | uniq -c
   16 avi
   29 jpg
  136 mp3
    3 mp4

Explicação do comando

  • find imprime recursivamente todos os nomes de arquivos
  • sed exclui de todo nome de arquivo o prefixo até a extensão do arquivo
  • uniq assume entrada classificada
    • -c faz a contagem (como um histograma).
maxschlepzig
fonte
Eu tenho um script semelhante. Simples e rápido.
Rufo El Magufo
Alguns dos arquivos têm o nome *.php?blah=blah&foo=barcom vários argumentos, portanto, todos são considerados únicos. Como posso modificá-lo para procurar *.php*?
precisa saber é o seguinte
3
Você pode tentar usar uma expressão sed diferente, por exemplosed 's/^.*\(\.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]\).*$/\1/'
maxschlepzig
Obrigado por explicar o que cada parte faz. Tantas respostas sobre tópicos semelhantes pulam esta parte. / aprendendo a pescar
MechEthan
11
@ bela83, as variantes de remoção dependem da avaliação de curto-circuito - assim, minha primeira versão find -name '.*' -prune -o -type f -printavalia como: se a entrada do diretório corresponder .*e a remover, caso contrário, se for um arquivo, imprima-a. Como .*também corresponde ., ou seja, o CWD, tudo é removido, ou seja, o find nem sequer desce para o primeiro diretório. Talvez as versões de 2 anos de findcomportamento se comportassem de maneira diferente - ou era apenas uma supervisão minha na época. De qualquer forma, find -name '.*' -not -name . -prune -o -type f -printisso corrige.
Maxschlepzig
6

Com zsh:

print -rl -- **/?*.*(D.:e) | uniq -c |sort -n

O padrão **/?*.* corresponde a todos os arquivos que possuem uma extensão, no diretório atual e em seus subdiretórios recursivamente. O qualificador glob D permite zshpercorrer até diretórios ocultos e considerar arquivos ocultos, .seleciona apenas arquivos regulares. O modificador de histórico mantém apenas a extensão do arquivo. print -rlimprime uma correspondência por linha. uniq -cconta itens idênticos consecutivos (o resultado global já está classificado). A chamada final para sortclassificar os ramais por contagem de uso.

Gilles 'SO- parar de ser mau'
fonte
5

Este one-liner parece ser um método bastante robusto:

find . -type f -printf '%f\n' | sed -r -n 's/.+(\..*)$/\1/p' | sort | uniq -c

Ele find . -type f -printf '%f\n'imprime o nome da base de todos os arquivos regulares na árvore, sem diretórios. Isso elimina a necessidade de se preocupar com diretórios que possam estar presentes .no seu sedregex.

O sed -r -n 's/.+(\..*)$/\1/p'substitui o nome do arquivo recebido por apenas sua extensão. Por exemplo, .somefile.exttorna-se .ext. Observe a inicial .+no regex; isso resulta em qualquer correspondência que precise de pelo menos um caractere antes da extensão .. Isso evita que nomes de arquivos como .gitignoresejam tratados como sem nome e com a extensão '.gitignore', que é provavelmente o que você deseja. Caso contrário, substitua o .+por a .*.

O restante da linha é da resposta aceita.

Editar : se você deseja um histograma bem classificado no formato de gráfico de Pareto , basta adicionar outro sortao final:

find . -type f -printf '%f\n' | sed -r -n 's/.+(\..*)$/\1/p' | sort | uniq -c | sort -bn

Exemplo de saída de uma árvore de origem Linux integrada:

    1 .1992-1997
    1 .1994-2004
    1 .1995-2002
    1 .1996-2002
    1 .ac
    1 .act2000
    1 .AddingFirmware
    1 .AdvancedTopics
    [...]
 1445 .S
 2826 .o
 2919 .cmd
 3531 .txt
19290 .h
23480 .c
Gary R. Van Sickle
fonte
1

Coloquei um script bash na minha ~/binpasta chamada exhistcom este conteúdo:

#!/bin/bash

for d in */ ; do
        echo $d
        find $d -type f | sed -r 's/.*\/([^\/]+)/\1/' | sed 's/^[^\.]*$//' | sed -r 's/.*(\.[^\.]+)$/\1/' | sort | uniq -c | sort -nr
#       files only      | keep filename only          | no ext -> '' ext   | keep part after . (i.e. ext) | count          | sort by count desc
done

Qualquer que seja o diretório em que eu esteja, basta digitar 'exh', a guia o preenche automaticamente e vejo algo assim:

$ exhist
src/
      7 .java
      1 .txt
target/
     42 .html
     10 .class
      4 .jar
      3 .lst
      2 
      1 .xml
      1 .txt
      1 .properties
      1 .js
      1 .css

PS: Aparar a peça após o ponto de interrogação deve ser simples com outro comando sed, provavelmente após o último (não tentei): sed 's/\?.*//'

Zsolt Katona
fonte