Wer öfter mal was in der Shell macht kennt vermutlich das Kommando find
. Damit kann man sehr flexibel Dateien oder Verzeichnisse auf der Festplatte suchen. So findet man zum Beispiel alle Dateien die älter sind als 100 Tage:
1 |
find . -type f -mtime +100 |
Um die Größen aller Dateien zu bekommen kann man find bitten für jede Datei ein du
(Disk Usage) auszuführen:
1 |
find . -type f -mtime +100 -exec du -b {} \; |
Kann man machen, aber das bedeutet dass find
für jede einzelne Datei ein Kommando startet. Jetzt braucht du
nicht sehr lange für die Ausführung, aber wenn man stattdessen beispielsweise jeweils ein Perl-Skript starten muss wirkt sich das sehr negativ aus.
Wenn man nur wenige Fundstellen erwartet kann man folgendes machen:
1 |
du -b $(find . -type f -mtime +100) |
So wird vor der Ausführung von du
die Klammer expandiert und durch die Ausgabe von find
ersetzt. Das hat aber einen bedeutenden Haken: wenn sehr viele Dateien gefunden werden wird die Kommandozeile zu lang die man durch die Expansion erhält („-bash: /usr/bin/du: Argument list too long“) — Zeilen dürfen nicht beliebig lang werden (man findet die zulässige Länge mit getconf ARG_MAX
, muss von der Zahl aber noch die Größe der Umgebungsvariablen abziehen).
Um das zu umgehen ruft man klassisch xargs
zur Hilfe. Das sieht dann so aus:
1 |
find . -type f -mtime +100 -print0 | xargs -0 du -b |
Jetzt findet find
alle gesuchten Dateien und gibt deren Namen nullterminiert nach STDOUT. Von da liest xargs
ein und baut eine Kommandozeile mit du -b
. In diese Zeile werden so viele der eingegebenen Strings reingepackt wie möglich bevor du
ausgeführt wird.
Aber find braucht offenbar kein xargs
Man kommt — und das weiss ich erst neuerdings — auf das gleiche Ergebnis wenn man in find
statt des Semikolons ein Pluszeichen benutzt:
1 |
find . -type f -mtime +100 -exec du -b {} + |
Keine Ahnung wie das bislang an mir vorübergehen konnte, das macht einiges eleganter.
Wie komme ich jetzt an die Summe der Fundstellen?
Wenn man folgendes schreibt berechnet du
für jeden Aufruf eine Summe, mit dem grep
kann man sich die ansehen:
1 |
find . -type f -mtime +100 -exec du -bc {} + | grep total |
Bei vielen Dateien wird du
mehrfach aufgerufen, man bekommt also mehrere Summen. In meinem Beispiel finde ich gut 45000 Dateien, find
ruft dafür 19 Mal du auf, grep
gibt mir also 19 Zeilen mit jeweils einer ziemlich großen Zahl. Die gilt es aufzusummieren, das geht am einfachsten mit awk
:
1 |
find . -type f -mtime +100 -exec du -bc {} + | awk '/total/{ total += $1 }; END { print total }' |
Jetzt bekomme ich nur noch eine sehr große und sehr unleserliche Summe, die gibt mir die Summe der Größe aller gefundenen Dateien. Die kann awk
mir in GB umrechnen:
1 |
find . -type f -mtime +100 -exec du -bc {} + | awk '/total/{ total += $1 }; END { print total / (2**(30)) " GB" }' |
Somit habe ich einen leserlichen Wert, damit kann ich arbeiten.
Wenn es einen einfacheren Weg zum Ziel gibt: ich bin immer für Vorschläge offen!