TL; DR: Der beste Weg ist, -exec rm
statt zu verwenden -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
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
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
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 jedem foo/*
und foo/bar
vor jedem foo/bar/*
.
Dies kann mit umgekehrt werden -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Beachten Sie, dass jetzt alle foo/*
vorher erscheinen foo/
. Gleiches gilt für foo/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 absteigt b
.
-depth
macht find, um den Inhalt eines Verzeichnisses vor dem Verzeichnis selbst zu verarbeiten. Das heißt, bis find den Verzeichniseintrag verarbeiten kann, ist b
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:
find a -not -path "*/b*" -type f -delete
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 sehr b
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 ist bar
. -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 von find
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 Namen b
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
und b
als Platzhalter verwendet haben und die richtigen Namen eher wie allosaurus
und sind brachiosaurus
. Wenn Sie brachiosaurus
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.
find a -not -path "*/b*" -type f -depth
a
außer eina/b
?