statystyki rekurencyjne dotyczące typów plików w katalogu?

65

Zrobiłem scrape strony internetowej dla projektu konwersji. Chciałbym zrobić kilka statystyk dotyczących rodzajów plików tam zawartych - na przykład 400 .htmlplików, 100 .gifitd. Jak to łatwo zrobić? To musi być rekurencyjne.

Edycja: Ze skryptem opublikowanym przez maxschelpzig mam problemy z architekturą strony, którą zeskrobałem. Niektóre pliki mają *.php?blah=blah&foo=barróżne argumenty, dlatego wszystkie są traktowane jako unikalne. Tak więc rozwiązanie należy uznać *.php*za tego samego typu, że tak powiem.

użytkownik394
źródło

Odpowiedzi:

96

Możesz użyć findi uniqdo tego np .:

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

Wyjaśnienie polecenia

  • find rekurencyjnie drukuje wszystkie nazwy plików
  • sed usuwa z każdej nazwy pliku prefiks aż do rozszerzenia pliku
  • uniq zakłada posortowane dane wejściowe
    • -c robi liczenie (jak histogram).
maxschlepzig
źródło
Mam podobny skrypt. Prosty i szybki.
Rufo El Magufo
Niektóre pliki mają *.php?blah=blah&foo=barróżne argumenty, dlatego wszystkie są traktowane jako unikalne. Jak mogę go zmienić, aby szukać *.php*?
user394,
3
Możesz spróbować użyć innego wyrażenia sed, np.sed 's/^.*\(\.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]\).*$/\1/'
maxschlepzig
Dziękujemy za poświęcenie czasu na wyjaśnienie, co robi każda porcja. Tak wiele odpowiedzi na podobne tematy pomija tę część. / learning-to-fish
MechEthan
1
@ bela83, warianty przycinania opierają się na ocenie zwarć - dlatego moja pierwsza wersja find -name '.*' -prune -o -type f -printocenia następująco: jeśli wpis katalogu pasuje, .*to przycinaj go, w przeciwnym razie, jeśli jest to plik, wydrukuj go. Ponieważ .*także pasuje ., tj. CWD, wszystko jest przycinane, tzn. Find nawet nie schodzi do pierwszego katalogu. Być może 2 lata stare wersje findzachowywał się różnie - czy była to tylko przeoczenie ze mnie wtedy. W każdym razie find -name '.*' -not -name . -prune -o -type f -printto naprawia.
maxschlepzig
6

Z zsh:

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

Wzór **/?*.* pasuje do wszystkich plików, które mają rozszerzenie w bieżącym katalogu i jego podkatalogów rekurencyjnie. Glob kwalifikator D niech zshtrawers nawet ukryte katalogi i rozważyć ukryte pliki, .wybiera tylko zwykłe pliki. Historia modyfikator zachowuje jedynie rozszerzenie pliku. print -rldrukuje jedno dopasowanie w linii. uniq -cliczy kolejne identyczne elementy (wynik globu jest już posortowany). Ostatnie wywołanie sortsortujące rozszerzenia według liczby użytkowników.

Gilles
źródło
5

Ten jednowarstwowy wydaje się być dość solidną metodą:

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

Wyświetla find . -type f -printf '%f\n'basename każdego zwykłego pliku w drzewie, bez katalogów. To eliminuje konieczność martwienia się o katalogi, które mogą znajdować .się w twoim sedwyrażeniu regularnym.

sed -r -n 's/.+(\..*)$/\1/p'Zastępuje przychodzącego pliku tylko jego przedłużenia. Np . .somefile.extStaje się .ext. Zwróć uwagę na inicjał .+wyrażenia regularnego; skutkuje to każdym dopasowaniem wymagającym przynajmniej jednego znaku przed rozszerzeniem .. Zapobiega .gitignoreto traktowaniu nazw plików, takich jak brak nazwy, i rozszerzeniu „.gitignore”, które prawdopodobnie jest tym, czego chcesz. Jeśli nie, wymień .+z .*.

Reszta linii pochodzi z zaakceptowanej odpowiedzi.

Edycja : Jeśli chcesz dobrze posortowany histogram w formacie wykresu Pareto , po prostu dodaj kolejny sortna końcu:

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

Przykładowe dane wyjściowe z wbudowanego drzewa źródeł Linux:

    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
źródło
1

W moim ~/binfolderze umieściłem skrypt bash exhisto tej treści:

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

Niezależnie od tego, w którym katalogu się znajduję, po prostu wpisuję „exh”, karta automatycznie go uzupełnia i widzę coś takiego:

$ 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 Przycinanie części po znaku zapytania powinno być łatwe do wykonania z innym poleceniem sed prawdopodobnie po ostatnim (nie próbowałem): sed 's/\?.*//'

Zsolt Katona
źródło