rekursive Statistiken über Dateitypen im Verzeichnis?

65

Ich habe ein Website-Scrape für ein Conversion-Projekt durchgeführt. Ich möchte einige Statistiken über die Dateitypen dort erstellen - zum Beispiel 400 .htmlDateien, 100 .gifusw. Was ist ein einfacher Weg, dies zu tun? Es muss rekursiv sein.

Bearbeiten: Mit dem Skript, das maxschelpzig gepostet hat, habe ich einige Probleme aufgrund der Architektur der Website, die ich geschabt habe. Einige der Dateien haben den Namen *.php?blah=blah&foo=barmit verschiedenen Argumenten, sodass sie alle als eindeutig gelten. Die Lösung muss *.php*also sozusagen alle vom selben Typ sein.

user394
quelle

Antworten:

96

Sie könnten findund uniqdafür verwenden, zB:

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

Befehlserklärung

  • find druckt rekursiv alle Dateinamen
  • sed löscht von jedem Dateinamen das Präfix bis zur Dateierweiterung
  • uniq setzt sortierte Eingabe voraus
    • -c Zählt wie ein Histogramm.
maxschlepzig
quelle
Ich habe ein ähnliches Skript. Einfach und schnell.
Rufo El Magufo
Einige der Dateien haben den Namen *.php?blah=blah&foo=barmit verschiedenen Argumenten, sodass sie alle als eindeutig gelten. Wie kann ich es ändern, um zu suchen *.php*?
user394
3
Sie können versuchen, einen anderen sed-Ausdruck zu verwenden, z. B.sed 's/^.*\(\.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]\).*$/\1/'
maxschlepzig
Vielen Dank, dass Sie sich die Zeit genommen haben, um zu erklären, was die einzelnen Teile bewirken. So viele Antworten zu ähnlichen Themen überspringen diesen Teil. / Fischen
lernen
1
@ bela83, die Prune-Varianten basieren auf Kurzschlussauswertung - meine erste Version find -name '.*' -prune -o -type f -printwertet also wie .*folgt aus : Wenn der Verzeichniseintrag übereinstimmt, dann schneide ihn ab, andernfalls, wenn es sich um eine Datei handelt, drucke ihn aus. Da .*auch Übereinstimmungen ., dh der CWD, vorhanden sind, wird alles gelöscht, dh find steigt nicht einmal in das erste Verzeichnis ab. Vielleicht findverhielten sich 2 Jahre alte Versionen anders - oder es war damals nur ein Versehen von mir. Jedenfalls find -name '.*' -not -name . -prune -o -type f -printbehebt dies.
maxschlepzig
6

Mit zsh:

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

Das Muster **/?*.* entspricht rekursiv allen Dateien mit einer Erweiterung im aktuellen Verzeichnis und seinen Unterverzeichnissen. Mit dem Glob-Qualifikator können D Sie zshsogar versteckte Verzeichnisse durchlaufen und versteckte Dateien berücksichtigen. Dabei werden .nur normale Dateien ausgewählt. Der Verlaufsmodifikator behält nur die Dateierweiterung bei. print -rldruckt eine Übereinstimmung pro Zeile. uniq -czählt aufeinanderfolgende identische Elemente (das Glob-Ergebnis ist bereits sortiert). Der letzte Aufruf zum sortSortieren der Nebenstellen nach Verwendungsanzahl.

Gilles
quelle
5

Dieser Einzeiler scheint eine ziemlich robuste Methode zu sein:

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

Das find . -type f -printf '%f\n'druckt den Basisnamen jeder regulären Datei im Baum ohne Verzeichnisse. So müssen Sie sich keine Gedanken mehr über Verzeichnisse machen, die möglicherweise .in Ihrem sedregulären Ausdruck enthalten sind.

Das sed -r -n 's/.+(\..*)$/\1/p'ersetzt den eingehenden Dateinamen nur mit seiner Erweiterung. ZB .somefile.extwird .ext. Beachten Sie die Initiale .+im regulären Ausdruck. Dies führt dazu, dass eine Übereinstimmung mindestens ein Zeichen vor der Erweiterung benötigt .. Dies verhindert, dass Dateinamen wie .gitignore".gitignore" so behandelt werden, dass sie überhaupt keinen Namen haben, und dass die Erweiterung ".gitignore" angezeigt wird. Wenn nicht, ersetzen Sie die .+durch a .*.

Der Rest der Zeile stammt aus der akzeptierten Antwort.

Bearbeiten : Wenn Sie ein gut sortiertes Histogramm im Pareto-Diagrammformat wünschen , fügen Sie sortam Ende einfach ein weiteres hinzu :

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

Beispielausgabe aus einem erstellten Linux-Quelltextbaum:

    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
quelle
1

Ich habe ein Bash-Skript mit folgendem Inhalt in meinen ~/binOrdner gelegt exhist:

#!/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

Egal in welchem ​​Verzeichnis ich mich befinde, ich gebe einfach 'exh' ein, der Tabulator vervollständigt es automatisch und ich sehe so etwas:

$ 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 Das Trimmen des Teils nach dem Fragezeichen sollte einfach mit einem anderen sed-Befehl möglich sein, wahrscheinlich nach dem letzten (ich habe es nicht ausprobiert): sed 's/\?.*//'

Zsolt Katona
quelle