Effizientes Löschen eines großen Verzeichnisses mit Tausenden von Dateien

162

Wir haben ein Problem mit einem Ordner, der mit Hunderttausenden winziger Dateien unhandlich wird.

Es gibt so viele Dateien, bei deren Ausführung rm -rfein Fehler ausgegeben wird. Stattdessen müssen wir Folgendes tun:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

Dies funktioniert, ist jedoch sehr langsam und führt ständig dazu, dass nicht genügend Arbeitsspeicher zur Verfügung steht.

Gibt es einen besseren Weg, dies zu tun? Im Idealfall möchte ich das gesamte Verzeichnis entfernen, ohne auf den Inhalt zu achten.

Toby
quelle
16
rm -rf *im Ordner scheitert wahrscheinlich an zu vielen Argumenten; aber was ist, rm -rf folder/wenn Sie das gesamte Verzeichnis trotzdem entfernen möchten?
Sr_
4
Anstatt es manuell zu löschen, empfehle ich, den Ordner auf einer separaten Partition zu haben und einfach das && Format && erneut einzuhängen.
bbaja42
7
Nur aus Neugier - wie viele Dateien braucht es, um zu brechen rm -rf?
JW013
7
Sie sollten die Frage wahrscheinlich genauer umbenennen, z. B. "Ein großes Verzeichnis mit Tausenden von Dateien effizient löschen". Um ein Verzeichnis und seinen Inhalt zu löschen , ist per Definition eine Rekursion erforderlich. Sie können die Verknüpfung nur für den Verzeichnisknoten selbst manuell aufheben (möglicherweise sind Root-Berechtigungen erforderlich), das Dateisystem aushängen und darauf ausführen fsck, um die nicht verwendeten Festplattenblöcke zurückzugewinnen. Dieser Ansatz scheint jedoch riskant zu sein und ist möglicherweise nicht schneller. Darüber hinaus kann die Dateisystemprüfung ein rekursives Durchlaufen des Dateisystembaums beinhalten.
JW013
4
Nachdem ich einen ccacheso großen Dateibaum hatte und rmso lange brauchte (und das gesamte System träge machte), war es erheblich schneller, alle anderen Dateien aus dem Dateisystem zu kopieren, zu formatieren und zurück zu kopieren. Seitdem gebe ich solchen massiven kleinen Dateibäumen ein eigenes Dateisystem, so dass Sie mkfsdirekt statt rm.
Frostschutz

Antworten:

213

Die Verwendung von rsync ist überraschend schnell und einfach.

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/

@saraths Antwort erwähnte eine weitere schnelle Wahl: Perl! Die Benchmarks sind schneller als rsync -a --delete.

cd yourdirectory
perl -e 'for(<*>){((stat)[9]<(unlink))}'

Quellen:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/was-ist-die-schnellste-Methode-zum-Löschen-von-Dateien-in-linux
Stevendaniels
quelle
4
Danke, sehr nützlich. Ich benutze Rsync die ganze Zeit, ich hatte keine Ahnung, dass Sie es verwenden könnten, um so zu löschen. Sehr viel schneller als rm-rf
John Powell
22
rsynckann schneller als rmnormal sein, da die Löschvorgänge in der richtigen Reihenfolge garantiert werden, sodass weniger Berechnungen für die Btress erforderlich sind. Siehe diese Antwort serverfault.com/a/328305/105902
Marki555
7
Kann jemand den Perl-Ausdruck so ändern, dass alle Verzeichnisse und Dateien in einem directory_to_be_deleted rekursiv gelöscht werden ?
Abhinav
5
Anmerkungen: -POption zu rsync hinzufügen , um mehr Anzeige zu erhalten. Achten Sie auch auf die Syntax. Die nachgestellten Schrägstriche sind obligatorisch. Schließlich können Sie den Befehl rsync ein erstes Mal starten, wobei Sie die -nOption haben, zuerst einen Probelauf zu starten .
Drasill
1
-agleich -rlptgoD, aber zum Löschen ist nur -rdnötig
Koen.
38

Jemand auf Twitter schlug vor, -deleteanstelle von-exec rm -f{} \;

Dies hat die Effizienz des Befehls verbessert. Es wird jedoch immer noch die Rekursion verwendet, um alles zu durchlaufen.

Toby
quelle
11
Dies ist kein Standard. GNU findhaben -deleteund andere findvielleicht.
Enzotib
13
-deletesollte -exec rmaus Gründen der Sicherheit und Effizienz immer der Verfügbarkeit vorgezogen werden.
JW013
6
GNU ist der De-facto- Standard.
RonJohn
17

Was ist mit so etwas wie: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Sie können die Anzahl der gleichzeitig zu löschenden Dateien begrenzen, indem Sie das Argument für den Parameter ändern -n. Die Dateinamen mit Leerzeichen sind ebenfalls enthalten.

digital_infinity
quelle
2
Sie brauchen das -n 20Bit wahrscheinlich nicht , da sich xargs sowieso auf akzeptable Argumentlistengrößen beschränken sollte.
Nutzlos
Ja, du hast recht. Hier ist eine Notiz von man xargs: (...) max-chars characters per command line (...). The largest allowed value is system-dependent, and is calculated as the argument length limit for exec. Diese -nOption ist in solchen Fällen verfügbar, in denen xargs die CLI-Puffergröße nicht bestimmen kann oder wenn der ausgeführte Befehl einige Einschränkungen aufweist.
Digital_infinity
12

Ein cleverer Trick:

rsync -a --delete empty/ your_folder/

Es ist super CPU-intensiv, aber sehr, sehr schnell. Siehe https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/de/linux/a-fast-way-to-remove-huge-number-of-files.html

MZAweb
quelle
Es ist nicht so schnell, weil es den Verzeichnisinhalt ineffizient liest. In dieser Antwort finden Sie eine 10- mal
Marki555
2
@ Marki555: in der bearbeitung der frage werden 60 sekunden für rsync -a --deletevs 43 für gemeldet lsdent. Das Verhältnis 10x war für time ls -1 | wc -l vs time ./dentls bigfolder >out.txt(das ist ein teilweise fairer Vergleich wegen > filevs wc -l).
Hastur
Das Problem besteht, dass NONE der Befehle dort tatsächlich DO zum Löschen des gewünschten traversal Betrieb. Welchen Code geben sie? FUNKTIONIERT NICHT wie von Marki555 beschrieben.
Svartalf
11

Ich denke nicht, dass Sie das tun, was Sie zu tun glauben.

Zuerst habe ich eine große Anzahl von Dateien erstellt, um Ihre Situation zu simulieren:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done

Dann habe ich versucht, was ich erwartet hatte, und wie es sich anhört, als würdest du die Frage beantworten:

$ rm -r foo/*
bash: /bin/rm: Argument list too long

Aber das funktioniert:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory
Izkata
quelle
6
Dies ist die einzige Lösung, die funktioniert hat: rm -Rf bigdirectoryMehrmals ausführen. Ich hatte ein Verzeichnis mit Tausenden von Millionen Unterverzeichnissen und Dateien. Ich konnte nicht einmal lsoder findoder rsyncin diesem Verzeichnis ausführen , weil der Speicher voll war. Der Befehl wurde rm -Rfviele Male beendet (zu wenig Speicher) und löschte nur einen Teil der Milliarden von Dateien. Aber nach vielen Wiederholungsversuchen war es endlich soweit. Scheint die einzige Lösung zu sein, wenn der Speicher knapp wird.
Erik
6

Ich hatte die Gelegenheit zu testen , -deleteim Vergleich zu , -exec rm \{\} \;und für mich -deletewar die Antwort auf dieses Problem.

Mit -deletegelöscht die Dateien in einem Ordner von 400.000 Dateien mindestens 1000-mal schneller als rm.

Der Artikel 'Wie man eine große Anzahl von Dateien unter Linux löscht' legt nahe, dass es ungefähr dreimal schneller ist, aber in meinem Test war der Unterschied viel dramatischer.

user2365090
quelle
3
Mit find -execwird der rmBefehl für jede Datei einzeln ausgeführt, deshalb ist er so langsam.
Marki555,
5

Zu der -deleteobigen Option: Ich verwende sie, um eine große Anzahl (1M + est) Dateien in einem temporären Ordner zu entfernen, den ich erstellt und versehentlich vergessen habe, jede Nacht aufzuräumen. Ich habe meine Festplatte / Partition versehentlich gefüllt und nichts anderes als der find .Befehl konnte sie entfernen . Es ist langsam, zuerst habe ich verwendet:

find . -ls -exec rm {} \;

Aber das dauerte eine EXTREME Zeit. Es begann nach ungefähr 15 Minuten, um einige der Dateien zu entfernen, aber ich schätze, dass es weniger als ungefähr 10 pro Sekunde entfernte, nachdem es schließlich gestartet wurde. Also habe ich versucht:

find . -delete

Stattdessen lasse ich es jetzt laufen. Es scheint schneller zu laufen, obwohl es die CPU EXTREM belastet, was der andere Befehl nicht war. Es läuft seit ungefähr einer Stunde und ich denke, ich bekomme wieder Speicherplatz auf meinem Laufwerk und die Partition wird allmählich "kleiner", aber es dauert immer noch sehr lange. Ich bezweifle ernsthaft, dass es 1.000-mal schneller läuft als das andere. Wie in allen Dingen wollte ich nur auf den Kompromiss zwischen Raum und Zeit hinweisen. Wenn Sie die CPU-Bandbreite übrig haben (wir tun dies), führen Sie die letztere aus. Es hat meine CPU zum Laufen gebracht ( uptimeBerichte):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

Und ich habe gesehen, dass die durchschnittliche Auslastung über 30,00 liegt, was für ein stark ausgelastetes System nicht gut ist, aber für unser System, das normalerweise leicht ausgelastet ist, ist es für ein paar Stunden in Ordnung. Ich habe die meisten anderen Dinge auf dem System überprüft und sie reagieren immer noch, sodass wir vorerst in Ordnung sind.

Scotty
quelle
Wenn Sie verwenden execmöchten, möchten Sie mit ziemlicher Sicherheit nicht verwenden, -lsund do find . -type f -exec rm '{}' ++ ist schneller, da es rm so viele Argumente gibt, wie es gleichzeitig verarbeiten kann.
Xenoterracide
Ich denke, Sie sollten dies in eine eigene Antwort umwandeln. Es ist wirklich zu lang für einen Kommentar. Es hört sich auch so an, als hätte Ihr Dateisystem ziemlich teure Löschvorgänge. Neugierig, welches es ist? Sie können das find … -deletedurchlaufen niceoder ionice, das kann helfen. So könnten einige Mount-Optionen in weniger crashsichere Einstellungen geändert werden. (Und je nachdem, was sich noch im Dateisystem befindet, ist der schnellste Weg, alles zu löschen, häufig mkfs.)
derobert
3
Der Lastdurchschnitt ist nicht immer die CPU, sondern nur ein Maß für die Anzahl blockierter Prozesse im Zeitverlauf. Prozesse können auf der Datenträger-E / A blockieren. Dies ist wahrscheinlich der Fall.
Score_Under
Beachten Sie auch, dass der Lastdurchschnitt nicht die Anzahl der logischen CPUs berücksichtigt. Daher ist loadavg 1für Single-Core-Rechner dasselbe wie loadavg 64für 64-Core-Systeme - dh jede CPU ist zu 100% ausgelastet.
Marki555,
3

Es gibt einige Methoden, die zum Löschen einer großen Anzahl von Dateien unter Linux verwendet werden können. Sie können die Option find with delete verwenden, die schneller ist als die Option exec. Dann kannst du perl unlink benutzen, dann sogar rsync. So löschen Sie eine große Anzahl von Dateien unter Linux

sarath
quelle
3

Ziehen Sie die Verwendung von Btrfs-Volume in Betracht und löschen Sie einfach das gesamte Volume für ein solches Verzeichnis mit einer großen Anzahl von Dateien.

Alternativ können Sie eine FS-Image-Datei erstellen, diese dann aushängen und löschen, um alles wirklich schnell auf einmal zu entfernen.

Sergei
quelle
2

Unter der Annahme, dass GNU parallelinstalliert ist, habe ich Folgendes verwendet:

parallel rm -rf dir/{} ::: `ls -f dir/`

und es war schnell genug.

Nacho
quelle
1

Das Löschen von WIRKLICH GROSSEN Verzeichnissen erfordert einen anderen Ansatz, wie ich auf dieser Site erfahren habe - Sie müssen ionice verwenden. Es stellt (mit -c3) sicher, dass das Löschen nur durchgeführt wird, wenn das System über IO-Zeit verfügt. Die Systemlast wird nicht zu hoch und alles bleibt ansprechbar (obwohl meine CPU-Zeit für die Suche mit etwa 50% ziemlich hoch war).

find <dir> -type f -exec ionice -c3 rm {} \;
Gamma
quelle
5
Verwenden von +anstelle von \;würde dies beschleunigen, da mehr Argumente auf einmal an rm übergeben werden, weniger Forking
Xenoterracide
1
Warum nicht ionice -c3 find <dir> -type f -delete
jtgd
0
ls -1 | xargs rm -rf 

sollte im Hauptordner funktionieren

PsyStyle
quelle
1
lsfunktioniert aufgrund der Anzahl der Dateien im Ordner nicht. Dafür musste ich aber finddanke gebrauchen .
Toby
4
@Toby: Try ls -f, wodurch die Sortierung deaktiviert wird. Zum Sortieren muss das gesamte Verzeichnis in den zu sortierenden Speicher geladen werden. Eine unsortierte Datei lssollte in der Lage sein, ihre Ausgabe zu streamen.
Camh
1
Funktioniert nicht mit Dateinamen, die Zeilenumbrüche enthalten.
Maxschlepzig
@camh das stimmt. Das Entfernen von Dateien in sortierter Reihenfolge ist jedoch schneller als in unsortierter Reihenfolge (da der Btree des Verzeichnisses nach jedem Löschen neu berechnet wird). In dieser Antwort finden Sie ein Beispiel. Serverfault.com/a/328305/105902
Marki555 29.06.15
@maxschlepzig für solche Dateien können Sie verwenden find . -print0 | xargs -0 rm, die das Nullzeichen als Dateinamentrennzeichen verwenden.
Marki555,
0

Für Izkatas Hinweis oben:

Aber das funktioniert:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

Das hätte fast geklappt - oder hätte geklappt -, aber ich hatte einige Probleme mit der Erlaubnis. Dateien befanden sich auf einem Server, aber ich verstehe immer noch nicht, woher dieses Berechtigungsproblem kam. Wie auch immer, Terminal bat um Bestätigung für jede Datei. Die Anzahl der Dateien lag bei 20.000, daher war dies keine Option. Nach "-r" habe ich die Option "-f" hinzugefügt, sodass der gesamte Befehl " rm -r -f Ordnername / " lautete . Dann schien es gut zu funktionieren. Ich bin ein Neuling bei Terminal, aber ich denke, das war okay, oder? Vielen Dank!

user41527
quelle
0

Abhängig davon, wie gut Sie diese Dateien entfernen müssen, würde ich die Verwendung von vorschlagen shred.

$ shred -zuv folder

Wenn Sie das Verzeichnis löschen möchten, es aber nicht entfernen und neu erstellen können, empfehle ich, es zu verschieben und sofort neu zu erstellen.

mv folder folder_del
mkdir folder
rm -rf folder_del

Dies ist schneller, ob Sie es glauben oder nicht, da nur eine Inode geändert werden muss. Denken Sie daran: Sie können diesen Geschmack auf einem Multicore-Computer nicht wirklich parallelisieren. Es kommt auf den Festplattenzugriff an, der durch das RAID oder was Sie haben, begrenzt ist.

Polemon
quelle
1
shred funktioniert nicht mit vielen modernen Dateisystemen.
0

Wenn Sie Millionen von Dateien haben und jede der oben genannten Lösungen Ihr System in Stress versetzt, können Sie diese Inspiration ausprobieren:

Datei nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("$@")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

Und jetzt lösche die Dateien:

find /path/to/folder -type f -exec ./nice_delete {} \+

Find erstellt Stapel (siehe getconf ARG_MAX) von einigen Zehntausenden von Dateien und übergibt sie an nice_delete. Dadurch werden noch kleinere Stapel erstellt, um den Ruhezustand zu ermöglichen, wenn eine Überlastung festgestellt wird.

brablc
quelle
0

Wenn Sie nur viele Dateien so schnell wie möglich ls -f1 /path/to/folder/with/many/files/ | xargs rmentfernen möchten, funktioniert dies möglicherweise in Ordnung. Führen Sie es jedoch besser nicht auf Produktionssystemen aus, da Ihr System möglicherweise zu E / A-Problemen wird und Anwendungen während des Löschvorgangs hängen bleiben.

Dieses Skript funktioniert gut für viele Dateien und sollte sich nicht auf das Laden des Systems auswirken.

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done
Leon Kramer
quelle