Ich möchte rekursiv alle Dateien löschen a
, auf die seit einiger Zeit nicht mehr im Ordner zugegriffen wird , mit Ausnahme aller Dateien im Unterordner b
.
find a \( -name b -prune \) -o -type f -delete
Ich erhalte jedoch eine Fehlermeldung:
find: Die Aktion -delete aktiviert automatisch -depth, aber -prune führt nichts aus, wenn -depth aktiviert ist. Wenn Sie trotzdem weitermachen möchten, verwenden Sie einfach explizit die Option -depth.
Durch -depth
das Hinzufügen werden alle Dateien b
eingeschlossen, was nicht passieren darf .
Kennt jemand einen sicheren Weg, um diese Arbeit zu machen?
a
außer eina/b
?cd a && ls -d !(b/*)
funktionieren? (Um es zu tun, nurrm -r
anstattls -d
.)a
(außer Dateien untera/b
).-r
zu rm. Es scheint, dass das, worüber Sie fragen, ziemlich einfach mit dem erweiterten Globbing von bash beantwortet werden kann, und was Sie dann mit dem Ergebnis des Globbings tun, liegt bei Ihnen.Antworten:
TL; DR: Der beste Weg ist,
-exec rm
statt zu verwenden-delete
.Erläuterung:
Warum beschwert sich find, wenn Sie versuchen,
-delete
mit zu verwenden-prune
?Kurze Antwort: weil
-delete
impliziert-depth
und unwirksam-depth
macht-prune
.Bevor wir zur langen Antwort kommen, beobachten Sie zunächst das Verhalten des Findens mit und ohne
-depth
:Es gibt keine Garantie für die Bestellung in einem einzigen Verzeichnis. Es besteht jedoch die Garantie, dass ein Verzeichnis vor seinem Inhalt verarbeitet wird. Beachten Sie
foo/
vor jedemfoo/*
undfoo/bar
vor jedemfoo/bar/*
.Dies kann mit umgekehrt werden
-depth
.Beachten Sie, dass jetzt alle
foo/*
vorher erscheinenfoo/
. Gleiches gilt fürfoo/bar
.Längere Antwort:
-prune
verhindert, dass find in ein Verzeichnis absteigt. Mit anderen Worten,-prune
überspringt den Inhalt des Verzeichnisses. In Ihrem Fall wird-name b -prune
verhindert, dass die Suche in ein Verzeichnis mit dem Namen absteigtb
.-depth
macht find, um den Inhalt eines Verzeichnisses vor dem Verzeichnis selbst zu verarbeiten. Das heißt, bis find den Verzeichniseintrag verarbeiten kann, istb
sein Inhalt bereits verarbeitet. Somit-prune
ist-depth
in der Tat unwirksam .-delete
impliziert,-depth
dass zuerst die Dateien und dann das leere Verzeichnis gelöscht werden können.-delete
weigert sich, nicht leere Verzeichnisse zu löschen. Ich denke, es wäre möglich, eine Option hinzuzufügen, um-delete
das Löschen nicht leerer Verzeichnisse zu erzwingen und / oder zu verhindern-delete
, dass dies impliziert wird-depth
. Aber das ist eine andere Geschichte.Es gibt noch einen anderen Weg, um das zu erreichen, was Sie wollen:
Dies kann leichter zu merken sein oder auch nicht.
Dieser Befehl steigt immer noch in das Verzeichnis ab
b
und verarbeitet jede einzelne Datei darin nur-not
, um sie abzulehnen. Dies kann ein Leistungsproblem sein, wenn das Verzeichnis sehrb
groß ist.-path
funktioniert anders als-name
.-name
Stimmt nur mit dem Namen (der Datei oder des Verzeichnisses) überein, während er-path
mit dem gesamten Pfad übereinstimmt. Beobachten Sie zum Beispiel den Weg/home/lesmana/foo/bar
.-name -bar
wird übereinstimmen, weil der Name istbar
.-path "*/foo*"
wird übereinstimmen, da sich die Zeichenfolge/foo
im Pfad befindet.-path
hat einige Feinheiten, die Sie verstehen sollten, bevor Sie es verwenden. Lesen Sie die Manpage vonfind
für weitere Details.Beachten Sie, dass dies nicht 100% narrensicher ist. Es besteht die Möglichkeit von "False Positives". Die Art und Weise, wie der Befehl oben geschrieben wird, überspringt alle Dateien, deren übergeordnetes Verzeichnis mit dem Namen beginnt
b
(positiv). Es wird jedoch auch jede Datei übersprungen, mit deren Namenb
unabhängig von der Position im Baum begonnen wird (falsch positiv). Dies kann behoben werden, indem ein besserer Ausdruck als geschrieben wird"*/b*"
. Das bleibt als Übung für den Leser.Ich gehe davon aus, dass Sie
a
undb
als Platzhalter verwendet haben und die richtigen Namen eher wieallosaurus
und sindbrachiosaurus
. Wenn Siebrachiosaurus
anstelle von setzen,b
wird die Anzahl der falsch positiven Ergebnisse drastisch reduziert.Zumindest die Fehlalarme werden nicht gelöscht, so dass es nicht so tragisch ist. Darüber hinaus können Sie nach Fehlalarmen suchen, indem Sie zuerst den Befehl ohne ausführen
-delete
(aber denken Sie daran, das implizite zu platzieren-depth
) und die Ausgabe untersuchen.quelle
-not -path
war genau das Richtige! Danke für eine großzügige Erklärung!-not -path
funktioniert, während-prune
es nicht funktioniert, wäre hilfreich. Warum kann man-not -path
mit koexistieren-depth
?Verwenden Sie einfach
rm
anstelle von-delete
:quelle
rm
funktioniert und warumdelete
nicht?rm
aber kein Problem. Trotzdem wäre eine Ausarbeitung eine gute Sache.-delete
impliziert-depth
, was offensichtlich nicht funktionieren kann-prune
.-path
funktioniert, hört aber nicht auffind
, in Verzeichnissen abzusteigen, die es nicht erkunden muss.Die obigen Antworten und Erklärungen waren sehr hilfreich.
Ich verwende die Problemumgehungen von "-exec rm {} +" oder "-not -path ... -delete", aber diese können viel langsamer sein als "find ... -delete". Ich habe "find ..." gesehen. -delete "wird 5x schneller ausgeführt als" -exec rm {} + "in tiefen Verzeichnissen eines NFS-Dateisystems.
Die '-not path'-Lösung hat den offensichtlichen Aufwand, alle Dateien in den ausgeschlossenen Verzeichnissen und darunter zu betrachten.
Das "find .. -exec rm {} +" ruft rm auf, das Systemaufrufe ausführt:
Das "find -delete" führt Systemaufrufe aus:
Der Befehl "-exec rm {} +" rm führt den vollständigen Pfad zur Inode-Suche zweimal pro Datei aus, aber "find -delete" führt eine Statistik durch und hebt die Verknüpfung des Dateinamens im aktuellen Verzeichnis auf. Das ist ein großer Gewinn, wenn Sie viele Dateien in einem Verzeichnis entfernen.
(Jammern Modus an (sorry))
Es scheint, als würde das Design der Interaktion zwischen -depth, -delete und -prune die effizienteste Methode zum Löschen der allgemeinen Aktion "Dateien löschen, außer denen in -prune-Verzeichnissen" unnötig eliminieren.
Die Kombination von "-type f -delete" sollte ohne -depth ausgeführt werden können, da nicht versucht wird, Verzeichnisse zu löschen. Wenn "find" eine Aktion "-deletefile" hätte, die besagt, dass Verzeichnisse nicht gelöscht werden sollen, müsste -depth nicht impliziert werden.
Die Aufrufe xargs oder find -exec für den Befehl rm könnten beschleunigt werden, wenn rm die Option hätte, Dateinamen zu sortieren, Verzeichnisse zu öffnen und die Verknüpfung aufzuheben (dir_fd, Dateiname), anstatt die Verknüpfung der vollständigen Pfade aufzuheben. Das Unlinkat (dir_fd, Dateiname) wird bereits ausgeführt, wenn mit der Option -r durch Verzeichnisse rekursiert wird.
(Jammern Modus aus)
quelle