Wie finde ich Dateien und summiere ihre Größe?

12

Ich möchte eine Reihe von Dateien (basierend auf einem Platzhalterausdruck) finden und deren Festplattennutzung zusammenfassen.

Etwas wie das:

$ find . -name 'flibble*' -ctime +90 -exec du -sh {} \;

2.1G    ./flibble_116.log
2.1G    ./flibble_83.log
2.1G    ./flibble_211040_157.log
2.1G    ./flibble3747_51.log

Diese Arbeit. Aber es bringt nicht das Ergebnis, das ich suche. Es listet den von jeder Datei verwendeten Speicherplatz auf, während findsie durchlaufen wird.

Was ich möchte, ist die Summe dualler gefundenen Dateien.

Paul
quelle

Antworten:

12

Lösung

Indem Sie die Option -c(oder --total) an du(1)angeben, können Sie sie anweisen, eine Gesamtsumme zu erstellen. Wenn Ihre Implementierung du(1)eine dieser Optionen unterstützt, können Sie den gewünschten Effekt mit dem folgenden Befehl erzielen:

$ find . -name 'flibble*' -ctime +90 -exec du -shc {} +

BEARBEITEN: Beachten Sie, dass die Anzahl der Dateien, die die von Ihrem System maximal zulässige Anzahl von Parametern überschreitet, findmöglicherweise noch commandmehrmals ausgeführt wird. Einige Implementierungen du(1)unterstützen auch das Lesen der Dateinamen aus einer Datei, die nicht unter der genannten Einschränkung leidet:

$ find -name 'flibble*' -ctime +90 -print0 > filenames
$ du -shc --files0-from=filenames

Erläuterung

Der Unterschied zwischen der Semantik von -exec command {} \;und -exec command {} +ist der folgende:

  • command {} \;wird commandeinmal für jedes Ergebnis von ausgeführt find. Der Pfadname des Ergebnisses wird anstelle von übergeben {}.

    $ touch 1 2 3
    $ find  1 2 3 -maxdepth 0 -exec echo {} \;
    1
    2
    3
    
  • command {} +wird ausgeführt command, wenn alle Ergebnisse abgerufen wurden. Die Pfadnamen der Ergebnisse werden anstelle von übergeben {}.

    $ touch 1 2 3
    $ find  1 2 3 -maxdepth 0 -exec echo {} +
    1 2 3
    

Die -print0Option bewirkt find(1), dass die gefundenen Dateinamen in die durch das Nullzeichen getrennte Standardausgabe gedruckt werden, und die --files0-fromOption bewirkt du(1), dass die durch Null getrennten Dateinamen gelesen werden. Im Gegensatz zum neuen Zeilenzeichen wird das Nullzeichen möglicherweise nicht in einem Dateinamen angezeigt, sodass die Ausgabe eindeutig ist.

Um mehr über die Optionen von du(1)und zu erfahren find(1), sollten Sie die entsprechenden Manpages konsultieren:

$ man du
$ man find
Witiko
quelle
2
Sie können mehrere Summen erhalten, wenn die Anzahl der Dateien wichtig ist (1 KB +), da die Anzahl der Befehlszeilenargumente begrenzt ist.
Ychaouche
Ich kann @ychaouche bestätigen. Ich habe das Problem beim Versuch, die Größe von mehr als 30.000 Dateien zu ermitteln.
Adrien H
Wenn dies ein Problem ist, unterstützen einige Implementierungen du(1)auch das Lesen der Dateinamen aus einer Datei : find 1 2 3 -maxdepth 0 -print0 > filenames; du -shc --files0-from=filenames.
Witiko
4

Versuche dies:

du -c `find . -name 'flibble*' -ctime +90` | tail -1

Der ursprüngliche Befehl gibt du ein Argument und führt es dann aus, bis alle Argumente durchlaufen sind. Auf diese Weise geben Sie einfach alle Argumente auf einmal an, schneiden dann die einzelnen Größen ab und lassen nur die Summe übrig. Sie können das Rohr und den Schwanz entfernen, um die Größe jeder Datei anzuzeigen, wenn Sie möchten.

Andre S.
quelle
Dies führt nicht zu korrekten Ergebnissen mit Pfadnamen, die Leerzeichen enthalten. Der richtige Weg, dies zu tun, ist die -exec du -c {} +Option von find, die die Pfadnamen unverändert an weitergibt du.
Witiko
4

Sie können dies versuchen:

find . -name 'flibble*' -ctime +90 -exec du -ch {} + | grep total
skush
quelle
2

Ich würde finddie Größe selbst ausdrucken lassen und ein anderes Werkzeug verwenden, um die Summe zu berechnen:

find . -name 'flibble*' -ctime +90 -printf "%s\n" |
perl -lnE '$sum += $_} END {say $sum'

Wenn Sie auch die Dateinamen sehen möchten:

find . -name 'flibble*' -ctime +90 -printf "%s\t%p\n" |
perl -apE '$sum += $F[0]} END {say $sum'
Glenn Jackman
quelle
1

Ein Liner, der funktionieren sollte, um auf den meisten Systemen eine Gigabyte-Summe zu erhalten:

echo "$(( ($(find . -name 'flibble*' -ctime +90 -type f -printf '%k+' )0)/1024/1024 )) GB"
Robert Boyd
quelle