Como encontrar o tamanho total do arquivo agrupado por extensão

12

Eu trabalho em um cluster compartilhado com outros colegas. O disco rígido é limitado (e já está cheio em algumas ocasiões), então eu limpo minha parte ocasionalmente. Quero fazer isso rapidamente, então até agora faço isso criando uma lista de arquivos com mais de 100 MB com mais de 3 meses e vejo se ainda preciso deles.

Mas agora estou pensando que poderia haver uma pasta com mais de 1000 arquivos menores que eu sinto falta, então quero uma maneira fácil de ver se esse é o caso. Pela maneira como eu gero dados, ajudaria a obter uma lista do tamanho total por extensão. No contexto desta pergunta, 'extension' está como tudo atrás do último ponto no nome do arquivo.

Suponha que eu tenha várias pastas com vários arquivos:

folder1/file1.bmp   40 kiB
folder1/file2.jpg   20 kiB
folder2/file3.bmp   30 kiB
folder2/file4.jpg    8 kiB

É possível fazer uma lista do tamanho total do arquivo por extensão de arquivo, assim:

bmp 70 kiB
jpg 28 kiB

Não ligo para arquivos sem extensão, para que possam ser ignorados ou colocados em uma categoria.

Eu já passou por páginas man de ls, due find, mas eu não sei o que é a ferramenta certa para este trabalho ...

contra-modo
fonte
Esta questão não seria errado em codegolf.stackexchange.com :)
Doug McLean
@DougMcLean: você pode publicá-lo lá. ;)

Respostas:

16

Em um sistema GNU:

find . -name '?*.*' -type f -printf '%b.%f\0' |
  awk -F . -v RS='\0' '
    {s[$NF] += $1; n[$NF]++}
    END {for (e in s) printf "%15d %4d %s\n", s[e]*512, n[e], e}' |
  sort -n

Ou o mesmo com perl, evitando a -printfextensão do GNU find(ainda usando uma extensão GNU -print0, mas essa é mais amplamente suportada atualmente):

find . -name '?*.*' -type f -print0 |
  perl -0ne '
    if (@s = stat$_){
      ($ext = $_) =~ s/.*\.//s;
      $s{$ext} += $s[12];
      $n{$ext}++;
    }
    END {
      for (sort{$s{$a} <=> $s{$b}} keys %s) {
        printf "%15d %4d %s\n",  $s{$_}<<9, $n{$_}, $_;
      }
    }'

Dá uma saída como:

          12288    1 pnm
          16384    4 gif
         204800    2 ico
        1040384   17 jpg
        2752512   83 png

Se você quiser KiB, MiB... sufixos, pipe para numfmt --to=iec-i --suffix=B.

%b*512fornece o uso do disco, mas observe que, se os arquivos tiverem links físicos várias vezes, eles serão contados várias vezes, para que você veja uma discrepância com os durelatórios.

Stéphane Chazelas
fonte
Falha no MacOS (encontrar: -printf: desconhecido primária ou operador)
MichaelCodes
1
@ MichaelCodes, yes -printfé específico do GNU find, e foi por isso que eu disse em um sistema GNU .
Stéphane Chazelas 11/04/19
@ MichaelCodes, veja editar com uma perlalternativa que deve funcionar mesmo no macOS.
Stéphane Chazelas 11/04/19
O que é 1,4,2,17? A quantidade de arquivos para cada tipo?
Jorge Cornejo Bellido
3

Aqui está outra solução:

find . -type f |  egrep -o "\.[a-zA-Z0-9]+$" | sort -u | xargs -I '%' find . -type f -name "*%" -exec du -ch {} + -exec echo % \; | egrep "^\.[a-zA-Z0-9]+$|total$" | uniq | paste - -

A parte que obtém as extensões é:

find . -type f |  egrep -o "\.[a-zA-Z0-9]+$" | sort -u

Em seguida, procure os arquivos com uma extensão e imprima-os na tela também:

xargs -I '%' find . -type f -name "*%" -exec du -ch {} + -exec echo % \;

Em seguida, queremos manter a extensão e o total:

egrep "^\.[a-zA-Z0-9]+$|total$" | uniq

e mantenha na mesma linha:

paste - -
vahbuna
fonte
Funciona no MacOS.
MichaelCodes
2

Não é tão bom quanto a solução de Stephane, mas você pode tentar

find . -type f -name "*.png" -print0 | xargs -0r du -ch | tail -n1

onde você deve executar isso para cada tipo de arquivo.

contra-modo
fonte
1
Isso pressupõe que haja poucos arquivos png que apenas uma duchamada seja executada. Com o GNU xargs, você deseja adicionar a -rflag para que o du não seja executado quando não houver arquivo (caso contrário, você acabaria com o uso do disco do diretório atual). Você pode adicionar -type fou ! type devitar a contagem dos arquivos que estão nos diretórios cujo nome termina em .png.
Stéphane Chazelas
isso procura apenas uma extensão específica.
Rahul
Foi o que eu escrevi. Era preciso envolvê-lo em um script que itere sobre todas as extensões aplicáveis ​​para obter uma solução "completa".
Countermode #