Suchen Sie die Anzahl der Dateien für jede Erweiterung in einem Verzeichnis


10

Ich möchte die Anzahl der Dateien für jede Erweiterung in einem Verzeichnis sowie die Dateien ohne Erweiterung zählen.

Ich habe einige Optionen ausprobiert, aber noch keine funktionierende Lösung gefunden:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cist eine Option, funktioniert aber nicht, wenn keine Dateierweiterung vorhanden ist. Ich muss wissen, wie viele Dateien keine Erweiterung haben.

  • Ich habe auch versucht, eine Suchschleife in ein Array zu integrieren und dann die Ergebnisse zu summieren, aber zu diesem Zeitpunkt löst dieser Code einen nicht deklarierten Variablenfehler aus, jedoch nur außerhalb der Schleife:

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

    Dies löst eine nicht deklarierte Variable aus sowie sobald die Suchschleife abgeschlossen ist.

Antworten:


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

Erläuterung:

  • find "$path" -type f Holen Sie sich eine rekursive Liste aller Dateien im "$path"Ordner.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' Reguläre Ausdrücke:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ Ersetzen Sie alle Dateien ohne Erweiterung durch (keine).
    • s/.*\.// Holen Sie sich die Erweiterung der verbleibenden Dateien.
  • LC_COLLATE=C sort Sortieren Sie das Ergebnis und halten Sie die Symbole oben.
  • uniq -c Zählen Sie die Anzahl der wiederholten Einträge.

9

Verwenden von 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))

Die Ausgabe:

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

Sie können wahrscheinlich mit Listenverständnis ext = [ f.split('.')[-1] for f in os.listdir('./') ] davonkommen , wie Thatll es paar Zeilen kürzer und vielleicht mehr Pythonic machen
Sergiy Kolodyazhnyy

Vielen Dank für den Vorschlag, ich habe nur versucht, es so klar wie möglich zu schreiben ...
Ravexina

1
Klarheit ist die Tugend :) Besonders wenn es um Code und technische Dokumentation geht.
Sergiy Kolodyazhnyy

6

Wenn Sie GNU awk haben, könnten Sie so etwas tun

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

dh Konstruieren / Inkrementieren eines assoziativen Arrays, das im letzten .getrennten Feld eingegeben wurde , oder einer beliebigen festen Zeichenfolge, z. B. (none)wenn keine Erweiterung vorhanden ist.

mawkscheint kein Null-Byte-Datensatztrennzeichen zuzulassen - Sie können es mawkmit dem Standard-Zeilenumbruchtrennzeichen verwenden, wenn Sie sicher sind, dass Sie keine Zeilenumbrüche in Ihren Dateinamen behandeln müssen:

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

5

Mit Basic /bin/shoder sogar bashder Aufgabe kann es etwas schwierig sein, aber wie Sie in anderen Antworten sehen können, können die Tools, die mit aggregierten Daten arbeiten können, diese Aufgabe besonders einfach bewältigen. Ein solches Tool wäre die sqliteDatenbank.

Der sehr einfache Prozess zur Verwendung der sqliteDatenbank besteht darin, eine .csvDatei mit zwei Feldern zu erstellen : Dateiname und Erweiterung. Später sqlitekann eine einfache Aggregatanweisung COUNT()mit verwendet werden GROUP BY ext, um das Zählen von Dateien basierend auf dem Erweiterungsfeld durchzuführen

$ { 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_tbTabelle, von der ich denke, dass sie referenziert wird, aber die Tabellenspalten sind nirgendwo definiert, wo ich sie sehen kann?
WinEunuuchs2Unix

@ WinEunuuchs2Unix Sie sind in der CSV-Datei selbst definiert. Das macht der Erste printf. Und SQLite behandelt standardmäßig die erste Zeile der CSV-Datei als Spaltennamen.
Sergiy Kolodyazhnyy

1
Sehr beeindruckend! +1
WinEunuuchs2Unix

5

Verwenden von PowerShell, wenn dies eine Option ist:

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

oder kürzer unter Verwendung von Aliasen:

ls -file | group -n Extension

1
Beeindruckend! Tolle erste Antwort! Ich wusste nicht einmal, dass PowerShell für Linux existiert ... +1
Fabby

2
Vielen Dank. Es gibt es schon seit einiger Zeit plattformübergreifend und Open Source, aber es gab ein Muster für SO und SU, bei dem Fragen zum Shell-Scripting unter Windows häufig mit "Nun, installieren Sie Cygwin und verwenden Sie Bash, dann können Sie Folgendes tun ", daher habe ich gezögert, dasselbe für Linux SE-Sites mit Tools zu tun, die von Windows stammen. Dies war jedoch eine nette Aufgabe, die die Stärken von PowerShell sehr gut zeigt, ohne das alte Argument der Ausführlichkeit zu fordern.
Joey
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.