Trova il numero di file per ogni estensione in una directory


10

Voglio contare il numero di file per ogni estensione in una directory, nonché i file senza estensione.

Ho provato alcune opzioni, ma non ho ancora trovato una soluzione funzionante:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cè un'opzione ma non funziona se non è presente alcuna estensione di file. Devo sapere quanti file non hanno un'estensione.

  • Ho anche provato un ciclo find in un array e quindi sommando i risultati, ma in questo momento quel codice genera un errore variabile non dichiarato, ma solo al di fuori del loop:

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

    Ciò genera una variabile non dichiarata, nonché una volta completato il ciclo di ricerca.

Risposte:


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

Spiegazione:

  • find "$path" -type f ottenere un elenco ricorsivo di tutti i file nella "$path"cartella.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' espressioni regolari:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ sostituire tutti i file senza estensione con (nessuno).
    • s/.*\.// ottenere l'estensione dei file rimanenti.
  • LC_COLLATE=C sort ordina il risultato, mantenendo i simboli in alto.
  • uniq -c contare il numero di voci ripetute.

9

Utilizzando 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))

Il risultato:

Counter({'': 7,
         '.png': 4,
         '.mp3': 3,
         '.jpg': 3,
         '.mkv': 3,
         '.py': 1,
         '.swp': 1,
         '.sh': 1})

Probabilmente ext = [ f.split('.')[-1] for f in os.listdir('./') ] riuscirai a
cavartela

Grazie per il suggerimento, stavo solo cercando di scriverlo il più chiaro possibile ...
Ravexina,

1
La chiarezza è la virtù :) Soprattutto quando si tratta di codice e documentazione tecnica.
Sergiy Kolodyazhnyy,

6

Se hai GNU awk, potresti fare qualcosa del genere

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

cioè costruire / incrementare un array associativo codificato sull'ultimo .campo separato o una stringa fissa arbitraria come (none)se non ci fosse estensione.

mawknon sembra consentire un separatore di record a byte nullo - potresti usarlo mawkcon il separatore di newline predefinito se sei sicuro di non aver bisogno di occuparti di newline nei nomi dei tuoi file:

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

5

Con l'attività di base /bin/sho addirittura bashl'attività può essere un po 'difficile, ma come puoi vedere in altre risposte gli strumenti che possono lavorare su dati aggregati possono gestire tale attività in modo particolarmente semplice. Uno di questi strumenti sarebbe il sqlitedatabase.

Il processo molto semplice per utilizzare il sqlitedatabase sarebbe quello di creare un .csvfile con due campi: nome file ed estensione. Successivamente è sqlitepossibile utilizzare una semplice istruzione aggregata COUNT()con GROUP BY extper eseguire il conteggio dei file in base al campo di estensione

$ { 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

files_tbtabella penso che sia referenziato ma le colonne della tabella non sono definite da nessuna parte posso vedere?
WinEunuuchs2Unix

@ WinEunuuchs2Unix Sono definiti nel file CSV stesso. Questo è quello che fa il primo printf. E SQLite per impostazione predefinita tratterà la prima riga del file CSV come nomi di colonna.
Sergiy Kolodyazhnyy,

1
Molto impressionante! +1
WinEunuuchs2Unix

5

Utilizzando PowerShell se questa è un'opzione:

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

o più breve, usando alias:

ls -file | group -n Extension

1
Wow! Ottima prima risposta! Non sapevo nemmeno che PowerShell esistesse per Linux ... +1
Fabby,

2
Grazie. Esiste da un po 'di tempo e multipiattaforma, ma c'è stato un modello su SO e SU in cui alle domande per gli script di shell su Windows è stata spesso data risposta con "Bene, installa cygwin e usa bash, quindi puoi fare quanto segue ", quindi sono stato riluttante a fare lo stesso per i siti Linux SE con strumenti originati da Windows. Ma questo è stato un bel compito che mostra abbastanza bene i punti di forza di PowerShell senza invitare il vecchio argomento sulla verbosità.
Joey,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.