Generieren Sie die Verteilung der Dateigrößen über die Eingabeaufforderung

16

Ich habe ein Dateisystem mit ein paar Millionen Dateien und möchte eine rekursive Verteilung der Dateigrößen in einem bestimmten Verzeichnis sehen. Ich denke, dass dies mit etwas Bash / Awk Fu völlig machbar ist, aber eine Hand gebrauchen könnte. Grundsätzlich hätte ich gerne Folgendes:

1KB: 4123
2KB: 1920
4KB: 112
...
4MB: 238
8MB: 328
16MB: 29138
Count: 320403345

Ich denke, dass dies bei einer Schleife und einer bedingten log2-Dateigröße nicht so schlimm sein sollte, aber ich kann nicht so recht dahin kommen.

Verwandte Frage: Wie kann ich Dateien finden, die größer / kleiner als x Bytes sind? .

notpeter
quelle

Antworten:

21

Das scheint ziemlich gut zu funktionieren:

find . -type f -print0 | xargs -0 ls -l | awk '{size[int(log($5)/log(2))]++}END{for (i in size) printf("%10d %3d\n", 2^i, size[i])}' | sort -n

Die Ausgabe sieht folgendermaßen aus:

         0   1
         8   3
        16   2
        32   2
        64   6
       128   9
       256   9
       512   6
      1024   8
      2048   7
      4096  38
      8192  16
     16384  12
     32768   7
     65536   3
    131072   3
    262144   3
    524288   6
   2097152   2
   4194304   1
  33554432   1
 134217728   4
Dabei ist die Zahl auf der linken Seite die Untergrenze eines Bereichs von diesem Wert bis zum Zweifachen dieses Werts und die Zahl auf der rechten Seite die Anzahl der Dateien in diesem Bereich.

garyjohn
quelle
Ich habe Ihre Antwort bearbeitet, um find anstelle von ls zu verwenden, sodass sie rekursiv ist und keine Verzeichniszählung durchführt. Möchte jemand eine Pause einlegen, um die Ausgabe der linken Spalte zu verschönern?
Notpeter
Aber die ursprüngliche Frage war , über „Verteilung der Dateigrößen in einem bestimmten Verzeichnis“, so ist es nicht OK, um die Änderung lszu ein find. Ich stelle es wieder so wie es war.
Garyjohn
@notpeter: Entschuldigung, ich habe dich nicht als Autor der Frage erkannt. Ich habe meine Antwort geändert, damit sie rekursiv durchsucht wird. Auf meinem System ist die Verwendung xargsjedoch erheblich schneller als -exec, daher habe ich diese Methode verwendet.
Garyjohn
1
Keine Bange. Jetzt können wir einfach unsere Kommentare löschen, so als ob es immer die richtige Antwort wäre. ;)
notpeter
13

Basierend auf Gary Johns Antwort ist hier ein Einzeiler, der auch die Ausgabe für Menschen lesbar formatiert:

find . -type f -print0 | xargs -0 ls -l | awk '{ n=int(log($5)/log(2)); if (n<10) { n=10; } size[n]++ } END { for (i in size) printf("%d %d\n", 2^i, size[i]) }' | sort -n | awk 'function human(x) { x[1]/=1024; if (x[1]>=1024) { x[2]++; human(x) } } { a[1]=$1; a[2]=0; human(a); printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }'

Hier ist die erweiterte Version davon:

find . -type f -print0                                                   \ 
 | xargs -0 ls -l                                                        \
 | awk '{ n=int(log($5)/log(2));                                         \
          if (n<10) n=10;                                                \
          size[n]++ }                                                    \
      END { for (i in size) printf("%d %d\n", 2^i, size[i]) }'           \
 | sort -n                                                               \ 
 | awk 'function human(x) { x[1]/=1024;                                  \
                            if (x[1]>=1024) { x[2]++;                    \
                                              human(x) } }               \
        { a[1]=$1;                                                       \ 
          a[2]=0;                                                        \
          human(a);                                                      \
          printf("%3d%s: %6d\n", a[1],substr("kMGTEPYZ",a[2]+1,1),$2) }' 

In der ersten habe awkich eine minimale Dateigröße definiert, um alle Dateien mit weniger als 1 KB an einem Ort zu sammeln. Im zweiten awkSchritt human(x)wird die Funktion zum Erstellen einer für Menschen lesbaren Größe definiert. Dieser Teil basiert auf einer der Antworten hier: /unix/44040/a-standard-tool-to-convert-a-byte-count-into-human-kib-mib-etc -like-du-ls1

Die Beispielausgabe sieht folgendermaßen aus:

  1k:    335
  2k:     16
 32k:      5
128k:     22
  1M:     54
  2M:     11
  4M:     13
  8M:      3
dzsuz87
quelle
2

Versuche dies:

find . -type f -exec ls -lh {} \; | 
 gawk '{match($5,/([0-9.]+)([A-Z]+)/,k); if(!k[2]){print "1K"} \
        else{printf "%.0f%s\n",k[1],k[2]}}' | 
sort | uniq -c | sort -hk 2 

AUSGABE :

 38 1K
 14 2K
  1 30K
  2 62K
  12 2M
  2 3M
  1 31M
  1 46M
  1 56M
  1 75M
  1 143M
  1 191M
  1 246M
  1 7G

ERLÄUTERUNG:

  • find . -type f -exec ls -lh {} \;: einfach genug, finde Dateien im aktuellen Verzeichnis und starte ls -lhsie

  • match($5,/([0-9.]+)([A-Z]+)/,k);: Hiermit wird die Dateigröße extrahiert und jede Übereinstimmung im Array gespeichert k.

  • if(!k[2]){print "1K"}: Wenn k[2]undefiniert ist, ist die Dateigröße <1 KB. Da ich mir vorstelle, Sie interessieren sich nicht für so kleine Größen, wird das Skript 1Kfür alle Dateien gedruckt , deren Größe <= 1 KB ist.

  • else{printf "%.0f%s\n",k[1],k[2]} : Wenn die Datei größer als 1 KB ist, runden Sie die Dateigröße auf die nächste Ganzzahl und drucken Sie sie zusammen mit dem Modifikator (K, M oder G).

  • sort | uniq -c : Zählen Sie die Vorkommen jeder gedruckten Zeile (Dateigröße).

  • sort -hk 2: Sortieren nach dem zweiten Feld in lesbarem Format. Auf diese Weise 7Gwird nach sortiert 8M.

terdon
quelle
Ich schätze die Erklärungen, ich denke, es ist hilfreich für Leute, die versuchen, es herauszufinden. Das heißt, Ihr Skript funktioniert aus zwei Gründen nicht für mich: 1) Mein GNU LS ist alt und gibt für 'ls -lh' (Bytes nicht K / M / G / T) und 2) eine andere lesbare Größe aus Es gibt zu viele Eimer. Bei Dateigrößen zwischen 1 KB und 1 GB gibt es 2000 Buckets, von denen die Hälfte 1 KB und die Hälfte 1 MB groß sind. Aber es lohnt sich für 'uniq -c', das ist neu für mich.
Notpeter