Warum löschte find with -delete die Dateien in meinem / save / -Verzeichnis, wenn find without delete sie nicht finden konnte?

20

Ich möchte alle Dateien im aktuellen Verzeichnisbaum löschen, mit Ausnahme der Dateien in save. Ich habe diesen Befehl ausgeführt:

 find . \( -name save -prune \) -o -type f -ls | grep /save/

und es fand keine. Aber als ich diesen Befehl ausgeführt habe:

 find . \( -name save -prune \) -o -type f -delete

Alle diese Dateien in / save / waren weg. Was vermisse ich?

Otheus
quelle
4
Autsch ... ich habe heute etwas gelernt (dank dir). Und ich empfehle einen einfachen mv save/ ../some/safer/locationLöschbefehl vor einem solchen "generischen" Löschbefehl (... aber natürlich hätte ich vor Ihrem Post die gleiche Prüfung durchgeführt und wäre auf die gleiche Schwierigkeit gestoßen!). Suchen Sie nun nach einem guten "Undelete" für das Dateisystem, auf dem sich die Dateien befanden ^^
Olivier Dulac
3
Mein Schmerz ist deine Vorbeugung.
Otheus
1
1000 danke an dich. Code (oft?) Arbeitet auf mysteriöse Weise ...
Olivier Dulac
@lesmana Ich habe deine Antwort dort positiv bewertet.
Leider

Antworten:

26

-deleteimpliziert, -depthdass das nicht funktioniert -prune( -depthbeginnt mit den Blättern). Es gibt eine Warnung dazu im Handbuch der GNU-Version ( -deleteist eine FreeBSD-Erweiterung, die jetzt auch von GNU findund einigen anderen Implementierungen unterstützt wird).

info find --index-search=-delete

Die Verwendung der Aktion '-delete' in der Befehlszeile aktiviert automatisch die Option '-depth' (* note find Expressions: :). Dies kann überraschend sein, wenn Sie zuvor nur mit '-print' getestet haben. Daher sollten Sie in der Regel daran denken, '-depth' explizit zu verwenden.

info find --index-search=-prune

Da '-delete' '-depth' impliziert, kann die Verwendung von '-prune' in Kombination mit '-delete' durchaus dazu führen, dass mehr Dateien gelöscht werden, als Sie beabsichtigt haben.

Hier haben Sie die Möglichkeit, rmstattdessen Folgendes zu verwenden:

find . -name save -prune -o -type f -exec rm -f {} +

(Möglicherweise unsicher, wenn sich darin Verzeichnisse befinden, die von anderen geschrieben werden können, da Sie möglicherweise Dateien außerhalb der aktuellen Verzeichnisstruktur löschen, indem Sie Verzeichnisse durch Symlinks ersetzen, während Sie diesen Befehl ausführen.)

Eine sicherere Alternative:

find . -name save -prune -o -type f -execdir rm -f -- {} \;

Das hat zwar nicht das oben erwähnte Problem, bedeutet aber, dass eine rmDatei pro Datei ausgeführt wird. Das --ist für die FreeBSD-Implementierung notwendig, nicht für die GNU, der Dateinamen vorangestellt sind ./.

Alternativ, wie von Costas vorgeschlagen:

LC_ALL=C find . ! -name save ! -path '*/save/*' -type f -delete

(aber das steigt immer noch unnötigerweise in saveVerzeichnisse)

Das LC_ALL=Cist dort also *stimmt mit jeder Folge von Bytes überein (auch mit denen, die im aktuellen Gebietsschema keine gültigen Zeichen bilden). Beachten Sie, dass dies Auswirkungen auf die Sprache der Fehlermeldungen hat (Englisch anstelle der Sprache des Benutzers).

Stéphane Chazelas
quelle
Was ist die Sicherheitsfrage hier mit rm?
jrw32982 unterstützt Monica
@ jrw32982, siehe edit mit link zum GNU find manual
Stéphane Chazelas