Millionen von Dateien löschen

38

Ich hatte ein Verzeichnis mit Millionen von GIF-Bildern gefüllt. Zu viele für den Befehl rm.

Ich habe den Befehl find folgendermaßen ausprobiert:

find . -name "*.gif" -print0 | xargs -0 rm

Das Problem ist, dass es meinen Computer sehr stark blockiert und für Kunden Zeitüberschreitungen verursacht, da es sich um einen Server handelt.

Gibt es eine Möglichkeit, alle diese Dateien schneller zu löschen, ohne die Maschine zu sperren?

Corepuncher
quelle
Ich habe eine Löschrate von ungefähr 6 GB / h mit dem folgenden Befehl "nice find". Wahrscheinlich dauert es 48 Stunden, bis alle Dateien gelöscht sind "Event Horizont" mit rm Befehl, dann lief es weg.
3
Wäre das Entfernen des gesamten Verzeichnisses nicht wesentlich schneller? Nehmen Sie einfach die "guten" Dateien heraus, bevor Sie die verbleibenden
bereinigen
Nun, jede Datei ist im Moment schlecht, weil sie nach / dir_old verschoben wurde und ich das / dir neu erstellt habe. Aber stößt rmdir nicht auf die gleiche Einschränkung wie rm *?
@ Corepuncher: Ich würde erwarten, dass das Entfernen des gesamten Verzeichnisses (wie mit rm -rfwäre schneller. Es ist einen Versuch wert.
Jason R
Ich lasse zurzeit "rm -rf" für das Verzeichnis laufen. Es läuft jetzt seit über 20 Minuten ... noch keine Änderung der Festplattengröße. Aber es gab auch noch nicht automatisch "Argumentationsliste zu lang" zurück. Das einzige Problem ist, dass es meine Maschine wirklich hämmert und andere Dinge verlangsamt / ausfällt. Ich weiß nicht, wie lange ich es lassen soll.

Antworten:

44

Schneller ist nicht unbedingt das, was Sie wollen. Möglicherweise möchten Sie tatsächlich langsamer ausgeführt werden , sodass durch das Löschen weniger Ressourcen verbraucht werden, während es ausgeführt wird.

Verwenden Sie nice (1) , um die Priorität eines Befehls zu verringern.

nice find . -name "*.gif" -delete

Für I / O-gebundene Prozesse ist nice (1) möglicherweise nicht ausreichend. Der Linux-Scheduler berücksichtigt nicht nur die CPU, sondern auch die E / A-Priorität.

ionice -c 2 -n 7 find . -name "*.gif" -delete

Wenn dies nicht der Fall ist, können Sie auch einen Schlaf hinzufügen, um die Geschwindigkeit zu verringern.

find . -name "*.gif" -exec sleep 0.01 \; -delete
John Kugelman unterstützt Monica
quelle
3
wow ... Millionen von Dateien mit einem Schlaf von 0,1 s ... benötigen einen Tag für 864000 Dateien.
Glglgl
7
@glglgl Alles klar, schlauer Arsch. Ich habe das Timeout geändert. :-P
John Kugelman unterstützt Monica
28
Der Schlaf mag eine gute Wahl sein, aber schön geht nicht, da die Aufgabe hier IO-gebunden ist, nicht CPU-gebunden; Sie können stattdessen ionice versuchen. Beachten Sie, dass der Schlaf unbrauchbar wird, wenn er zu klein ist.
Matteo Italia
3
@glglgl: Der Punkt ist genau, dass, wenn Sie keine Dienstunterbrechung auf dem Server verursachen möchten, Sie langsam vorgehen müssen, die Zeit, in der dieser Code ruht, da ist, damit der Server tatsächlich nützliche Arbeit mit der Festplatte leistet.
Matteo Italia
1
+1 für die sleepHinzufügung - Ich hatte Probleme mit Servern, die an der E / A drosseln, obwohl sie verwendet wurden ionice -c 3. Es verlängert die Zeit, die zum Löschen der Dateien benötigt wird, erheblich (natürlich), aber ich würde lieber warten, als die Anwendung herunterzufahren ...
Ola Tuvesson,
22

Da Sie unter Linux arbeiten und diese Aufgabe wahrscheinlich an E / A gebunden ist, empfehle ich, Ihrem Befehl die Priorität des inaktiven E / A-Schedulers zuzuweisen, indem Sie Folgendes verwenden ionice(1):

ionice -c3 find . -name '*.gif' -delete

Im Vergleich zu Ihrem ursprünglichen Befehl kann dies sogar einige CPU-Zyklen ersparen, indem die Pipe zu vermieden wird xargs.


quelle
@ Braiam Was meinst du? Dies ist kein Ort, find ... -execan dem das Sinn macht.
Oh ja, entschuldigung. Mein Fehler. Bist du sicher, dass das effizient ist?
Braiam
1
Nun, die find(1)Dokumentation behauptet es. :) Und es sollte offensichtlich sein, dass es findeffizienter ist , sich Dateien entfernen zu lassen, als einen rmBefehl dafür zu geben.
1
Ich habe mehrere vorgeschlagene Versionen in einem Ordner mit 4 Millionen Dateien auf einem Produktionsserver ausprobiert und dieser ist der einzige, der das System nicht verschluckt. ionice -c3senkt den Prio, um nur ausgeführt zu werden, wenn das E / A im Leerlauf ist, andernfalls ist dies perfekt. Beachten Sie, -deletedass Sie mit diesem Befehl dasselbe tun können (einschließlich der Rückmeldung, dass es funktioniert) , da dies nicht der Standard für die Suche ist: ionice -c 3 find . -name '*.gif' -exec echo {} \; -exec rm {} \;- Langsame, aber keine Verzögerung wichtiger Prozesse.
Christopher Lörken
13

Nein.

Es gibt keinen schnelleren Weg, um vom Soft-Format der Festplatte abzuweichen. Die Dateien werden sofort an rm übergeben (bis zur Begrenzung der Befehlszeile, es könnte auch an die gesetzt werden xargs), was viel besser ist, als rm für jede Datei aufzurufen. Also nein, es gibt definitiv keinen schnelleren Weg.

Die Verwendung nice(oder reniceeines laufenden Prozesses) hilft nur teilweise, da dies zur Planung der CPU- Ressource und nicht der Festplatte dient! Und die CPU-Auslastung wird sehr gering sein. Dies ist eine Linux-Schwäche - wenn ein Prozess die Festplatte "auffrisst" (dh viel damit arbeitet), bleibt die gesamte Maschine hängen. Modifizierter Kernel für die Echtzeitnutzung könnte eine Lösung sein.

Was ich auf dem Server tun würde, ist , andere Prozesse manuell ihre Arbeit erledigen zu lassen - Pausen einschließen, damit der Server "atmet":

find . -name "*.gif" > files
split -l 100 files files.
for F in files.* do
    cat $F | xargs rm
    sleep 5 
done

Dies wird 5 Sekunden nach jeweils 100 Dateien warten. Es wird viel länger dauern, aber Ihre Kunden sollten keine Verzögerungen bemerken.

Tomas
quelle
"Die Dateien werden sofort an rm übergeben (bis zur Begrenzung der Befehlszeile). Wenn also die Shell angewiesen wird, rm *wird sie *mit allen Dateinamen in die Zeile eingeblendet und an übergeben rm? Das ist unglaublich dumm. Warum sollte Shell ?" Wildcards erweitern?
:-D @Joker_vD, machst du Witze, wie dein Name schon sagt? :-)
Tomas
2
@Joker_vD: Kompatibilität mit einer Unix-Entscheidung von 1970 oder so. Windows macht das nicht. Dort können Programme Platzhalter an FindNextFile / FindNextFile übergeben, sodass die Ergebnisse einzeln abgerufen werden.
MSalters
@Tomas In diesem Fall nicht. Ehrlich gesagt sehe ich sofort zwei Probleme mit einem solchen Design: Erstens ist die Befehlszeile kein Gummi; Zweitens kann das Programm nicht feststellen, ob es mit *oder aufgerufen wurde, /*und kann eine solche Entscheidung des Benutzers in Frage stellen.
1
@Joker_vD Es gibt viele gute Dinge an der Shell, die eine Wildcard-Erweiterung durchführen. Es unterscheidet sich von Windows, aber kommen Sie nicht zu dem Schluss, dass es unglaublich dumm ist, nur weil es sich von dem unterscheidet, was Sie gewohnt sind. Wenn Sie mehr wissen möchten, empfehlen wir Ihnen, Google it zu verwenden oder eine Frage auf der entsprechenden Stack Exchange-Website zu veröffentlichen. Es ist eine große Entgleisung für diesen Kommentarbereich.
John Kugelman unterstützt Monica
5

Wenn die Anzahl der zu löschenden Dateien die Anzahl der verbleibenden Dateien bei weitem übersteigt, ist es möglicherweise nicht die effizienteste Methode, den Baum der zu löschenden Dateien zu durchsuchen und alle diese Dateisystemaktualisierungen durchzuführen. (Es ist analog dazu, eine umständliche Speicherverwaltung mit Referenzzählung durchzuführen, jedes Objekt in einem großen Baum zu besuchen, um seine Referenz zu löschen, anstatt alles, was nicht mehr benötigt wird, in einem Schritt in Müll zu verwandeln und dann zu bereinigen.)

Das heißt, klonen Sie die Teile des Baums, die auf einem anderen Volume aufbewahrt werden sollen. Erstellen Sie auf dem ursprünglichen Volume ein neues, leeres Dateisystem. Kopieren Sie die gespeicherten Dateien wieder in ihre ursprünglichen Pfade. Dies ähnelt vage dem Kopieren der Speicherbereinigung .

Es wird einige Ausfallzeiten geben, diese sind jedoch möglicherweise besser als anhaltend schlechte Leistung und Betriebsstörungen.

Es mag in Ihrem System und Ihrer Situation unpraktisch sein, aber es ist leicht vorstellbar, dass dies der richtige Weg ist.

Angenommen, Sie möchten alle Dateien in einem Dateisystem löschen . Was wäre der Sinn, eins nach dem anderen zu wiederholen und zu löschen? Hängen Sie es einfach aus und erstellen Sie ein "mkfs" über der Partition, um ein leeres Dateisystem zu erstellen.

Oder möchten Sie alle Dateien mit Ausnahme von einem halben Dutzend wichtiger Dateien löschen? Holen Sie sich das halbe Dutzend da raus und ... "mkfs" übertrieben.

Irgendwann gibt es einen Break-Even-Punkt, an dem genügend Dateien verbleiben müssen, sodass das rekursive Löschen unter Berücksichtigung anderer Kosten wie Ausfallzeiten billiger wird.

Kaz
quelle
4

Hast du es versucht:

find . -name "*.gif" -exec rm {} +

Das + -Zeichen am Ende bewirkt, dass find weitere Dateien für den einzelnen auszuführenden Befehl rm enthält. Überprüfen Sie diese Frage für weitere Details.

Bartosz Firyn
quelle
Es wird viel schneller ausgeführt als -print0 | xargs-lösung, da der rm-prozess nicht für jede datei, sondern für einen großen satz von ihnen aufgerufen wird und daher eine geringere last verursacht.
@JohnKugelman Sie haben Recht, aber es ist eine GNU-Erweiterung, die mit dem nativen Befehl find nicht immer verfügbar ist .
CodeGnome
OK, interessant, aber das ist (wie auch -delete) eine ziemlich neue Sache, die nicht immer da sein muss ..
Tomas
Dies bringt jedoch sicherlich nichts Besseres im Vergleich zur OP-Lösung.
Tomas