Encontre o número de arquivos para cada extensão em um diretório

10

Quero contar o número de arquivos para cada extensão em um diretório, bem como os arquivos sem extensão.

Eu tentei algumas opções, mas ainda não encontrei uma solução funcional:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cé uma opção, mas não funciona se não houver extensão de arquivo. Preciso saber quantos arquivos não têm extensão.

  • Eu também tentei um loop de localização em uma matriz e, em seguida, somar os resultados, mas nesse momento esse código gera um erro de variável não declarado, mas apenas fora do loop:

    declare -a arr
    arr=()
    echo ${arr[@]}
    

    Isso lança uma variável não declarada, assim como quando o loop de busca é concluído.

menino trator
fonte

Respostas:

10
find "$path" -type f | sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' | LC_COLLATE=C sort | uniq -c

Explicação:

  • find "$path" -type f obtenha uma lista recursiva de todos os arquivos na "$path"pasta.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' expressões regulares:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ substitua todos os arquivos sem extensão por (nenhum).
    • s/.*\.// obtenha a extensão dos arquivos restantes.
  • LC_COLLATE=C sort classifique o resultado, mantendo os símbolos no topo.
  • uniq -c conte o número de entradas repetidas.
Helio
fonte
9

Usando Python:

import os
from collections import Counter
from pprint import pprint

lst = []
for file in os.listdir('./'):
        name, ext = os.path.splitext(file)
        lst.append(ext)

pprint(Counter(lst))

A saída:

Counter({'': 7,
         '.png': 4,
         '.mp3': 3,
         '.jpg': 3,
         '.mkv': 3,
         '.py': 1,
         '.swp': 1,
         '.sh': 1})
Ravexina
fonte
Você provavelmente pode ir longe com compreensão da lista, como ext = [ f.split('.')[-1] for f in os.listdir('./') ] Thatll torná-lo linhas par mais curto e talvez mais Pythonic
Sergiy Kolodyazhnyy
Obrigado por sugestão, eu estava apenas tentando escrevê-lo tão claro como eu poderia ...
Ravexina
11
A clareza é a virtude :) Especialmente quando se trata de código e documentação de engenharia.
Sergiy Kolodyazhnyy 03/09/19
6

Se você possui o GNU awk, pode fazer algo como

printf '%s\0' * | gawk 'BEGIN{RS="\0"; FS="."; OFS="\t"} 
  {a[(NF>1 ? $NF : "(none)")]++} 
  END{for(i in a) print a[i],i}
'

ou seja, construir / incrementar uma matriz associativa digitada no último .campo separado ou alguma sequência fixa arbitrária, como (none)se não houver extensão.

mawkparece não permitir um separador de registro de byte nulo - você pode usar mawko separador de nova linha padrão se tiver certeza de que não precisa lidar com novas linhas nos nomes de arquivos:

printf '%s\n' * | mawk 'BEGIN{FS="."; OFS="\t"} {a[(NF>1 ? $NF : "(none)")]++} END{for(i in a) print a[i],i}'
chave de aço
fonte
5

Com o básico /bin/shou mesmo basha tarefa, pode ser um pouco difícil, mas como você pode ver em outras respostas, as ferramentas que podem trabalhar com dados agregados podem lidar com essa tarefa de maneira particularmente fácil. Uma dessas ferramentas seria o sqlitebanco de dados.

O processo muito simples de usar o sqlitebanco de dados seria criar um .csvarquivo com dois campos: nome e extensão do arquivo. Mais tarde sqlitepode usar declaração agregado simples COUNT()com GROUP BY extpara realizar a contagem de arquivos com base no campo de extensão

$ { printf "file,ext\n"; find -type f -exec sh -c 'f=${1##*/};printf "%s,%s\n" "${1}" "${1##*.}"' sh {} \; ; }  > files.csv
$ sqlite3 <<EOF
> .mode csv
> .import ./files.csv files_tb
> SELECT ext,COUNT(file) FROM files_tb GROUP BY ext;
> EOF
csv,1
mp3,6
txt,1
wav,27
Sergiy Kolodyazhnyy
fonte
files_tbacho que a tabela está sendo referenciada, mas as colunas da tabela não estão definidas em nenhum lugar que eu possa ver?
WinEunuuchs2Unix
@ WinEunuuchs2Unix Eles são definidos no próprio arquivo csv. Isso é o que o primeiro printffaz. E o SQLite assumirá o padrão de tratar a primeira linha do arquivo csv como nomes de colunas.
Sergiy Kolodyazhnyy 03/09/19
11
Muito impressionante! +1
WinEunuuchs2Unix
5

Usando o PowerShell, se for uma opção:

Get-ChildItem -File | Group-Object Extension -NoElement

ou menor, usando aliases:

ls -file | group -n Extension
Joey
fonte
11
Uau! Ótima primeira resposta! Eu nem sabia que o PowerShell existia para Linux ... +1
Fabby 03/09
2
Obrigado. Ele existe entre plataformas e código aberto há algum tempo, mas existe um padrão no SO e no SU em que as perguntas sobre scripts de shell no Windows costumam ser respondidas com "Bem, instale o cygwin e use o bash, e você poderá fazer o seguinte ", por isso hesitei em fazer o mesmo nos sites Linux SE com ferramentas originadas no Windows. Mas essa foi uma boa tarefa que mostra os pontos fortes do PowerShell sem convidar o velho argumento sobre verbosidade.
Joey