Wie lösche ich Verzeichnisse, die auf der Ausgabe von "find" basieren?

148

Ich gebe den folgenden Befehl aus, um die .svn-Verzeichnisse zu finden:

find . -name ".svn"

Das gibt mir folgende Ergebnisse:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

Wie könnte ich all diese Zeilen verarbeiten rm -fr, um die Verzeichnisse und deren Inhalt zu löschen?

Arnaud
quelle
3
GNU find hat die -deleteOption.
Marco
5
Oder Sie können -exec rm -r "{}" \;das Ende des Funds ergänzen - seien Sie vorsichtig bei der Verwendung rm -r! :)
Drav Sloan
10
@Marco Die Löschoption scheint bei Verzeichnissen nicht zu funktionieren.
Arnaud
@ SuperChafouin Es funktioniert hier perfekt auf Dateien und Verzeichnissen. Der Punkt ist, dass es nur leere Verzeichnisse löscht und wenn Sie angeben, dass -name ".svn"es nur mit dem .svnVerzeichnis selbst und nicht mit den Dateien im .svnVerzeichnis übereinstimmt .
Marco
1
@SuperChafouin funktioniert aber nicht für Pfade mit Leerzeichen (daher -execmit Anführungszeichen "{}").
Drav Sloan

Antworten:

194

Find kann Argumente mit der -execOption für jede gefundene Übereinstimmung ausführen . Dies ist ein empfohlener Mechanismus, da Sie Pfade mit Leerzeichen / Zeilenumbrüchen und anderen Zeichen korrekt behandeln können. Sie müssen den Inhalt des Verzeichnisses löschen, bevor Sie das Verzeichnis selbst entfernen können. Verwenden Sie hierzu -rden rmBefehl.

Für Ihr Beispiel können Sie Folgendes ausgeben:

find . -name ".svn" -exec rm -r "{}" \;

Sie können find auch anweisen , nur Verzeichnisse mit dem Namen .svn zu finden, indem Sie einen Haken setzen -type d:

find . -name ".svn" -type d -exec rm -r "{}" \;

Warnung Verwenden Sie rm -rmit Vorsicht löscht den Ordner und seinen Inhalt.

Wenn Sie nur leere Verzeichnisse sowie Verzeichnisse löschen möchten, die nur leere Verzeichnisse enthalten, können Sie dies mit -deleteund tun -empty:

find . -name ".svn" -type d -empty -delete
Drav Sloan
quelle
22
Ich habe gesehen Beratung immer laufen , -type nachdem -name in Fund Befehlen, da Anrufe an statdie Art zu erhalten teuer sind. Ich habe es nur selbst mit einer ziemlich großen Anzahl von Dateien versucht, und es scheint wahr zu sein: Das Ausführen find . -name 'foo' -type ddauerte 19 Sekunden, während es find . -type d -name 'foo'32 Sekunden dauerte. Also ca. 50% längere Zeit zum -typeersten Mal laufen .
Spinup
6
Ich benutze diesen Befehl seit Jahren, aber auf dem Mac erhalte ich jetzt die Fehlermeldung, dass diese Verzeichnisse nicht existieren. Auch wenn es sie löscht. Ich habe noch nie Nachrichten gesehen.
Chovy
1
Gleich wie @chovy. Gibt es eine Möglichkeit, diese Nachrichten loszuwerden?
Clément
2
@chovy @ clément Das liegt daran find, dass in diesem Ordner nach anderen Übereinstimmungen gesucht werden soll , während gleichzeitig der Ordner entfernt wird. ~ Ich weiß noch nicht, wie ich das beheben soll. ~ Dirty Fix:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie
5
@chovy @ Clément Ich denke, das -depthArgument behebt dies:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
Gimboland
67

Hier ist ein tragbarer noch schneller als der akzeptierte Antwortweg.

Die Verwendung eines +anstelle eines Semikolons als findBefehlsabschlusszeichen optimiert die CPU-Auslastung. Das kann von Bedeutung sein, wenn Sie viele .svnUnterverzeichnisse haben:

find . -name .svn -type d -exec rm -rf {} +

Beachten Sie auch , dass Sie nie ein Bedürfnis hier die geschweiften Klammern zitieren.

1 Es sei denn, Sie verwenden die fishShell.

jlliagre
quelle
5
Was ist der Unterschied zwischen + und Semikolon? Warum verwenden wir keine geschweiften Klammern?
Shicheng Guo
1
@ShichengGuo Mit dem Semikolon wird ein rm-Befehl pro Verzeichnis gefunden, mit dem + wird ein einziger rm-Befehl alle gefundenen Verzeichnisse (oder zumindest eine sehr große Anzahl von ihnen) verarbeiten. Ich verstehe Ihre zweite Frage nicht, geschweift Klammern werden hier verwendet.
Juli
Ich denke, @ShichengGuo bedeutet, warum müssen wir hier nicht die geschweiften Klammern zitieren (@jlliagre schrieb, dass wir sie niemals zitieren müssen). Ich kann jetzt keine Referenz finden, aber ich verstehe, dass find die Pfade, die durch {} ersetzt wurden, automatisch verlässt.
Quinn Comendant
Die Antwort und die Frage stimmen nicht ganz. Wenn viele Dateien gefunden werden, dann ';' würde "Befehlszeile zu lang" Fehler geben. + teilt die in Stapeln gefundenen Dateien, die kürzer als die maximal zulässige Befehlszeilenlänge sind, und führt den Befehl für jeden Stapel aus.
Gaoithe
1
@gaoithe Ich habe einen Rollback durchgeführt, der eine korrekte Aussage durch eine falsche ersetzt hat. Die Verwendung + ist die CPU - Auslastung zu reduzieren, verwenden ; nicht zu lang Fehler auf einen Befehl führen.
Juli
27

Angenommen, Sie verwenden gnu find , können Sie die folgende -deleteOption verwenden:

find . -name test -delete

das ist leichter zu merken.

Chun Yang
quelle
Erwägen Sie, Ihren Beitrag mit einer Erläuterung des Befehls (oder einer Dokumentation zum Sichern Ihrer Lösung) zu erweitern. Oft sind eine (oder zwei) Zeilenantworten nicht besonders aufschlussreich.
HalosGhost
94
Dies funktioniert nicht bei nicht leeren Verzeichnissen.
Belacqua
2
funktioniert auch unter Mac OS X
Unentschieden
Dies funktioniert nicht für nicht leere Ordner, aber es ist die einfachere und sicherere Lösung
RousseauAlexandre
Die Optionen Auftrag ist sehr wichtig, sie so um ausführen wird finden, -delete haben die letzte sein
Jose Ignacio Centeno
13

Auf meinem Computer, wenn ich Folgendes verwende:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Die Verzeichnisse werden gelöscht, aber ich erhalte den Fehler:

find: ‘./dirname’: No such file or directory

für jedes Verzeichnis.

Meine Verzeichnisse sind nicht leer, daher funktioniert die Option -delete bei mir nicht. Den Grund für dieses Verhalten habe ich hier gefunden :

  1. find benötigt (nicht unbedingt) den ersten Eintrag im Verzeichnis ./. das wäre zB dir.1 /
  2. es vergleicht es mit dem Muster "dir.?". passt es zusammen Ja.
  3. find führt "rm -r dir.1" aus.
  4. find versucht, dir.1 / einzugeben, um das Muster im Verzeichnis zu finden. Es weiß nichts über den Befehl exec.
  5. es findet dir.1 / nicht mehr. gibt ENOENT zurück (siehe die Ausgabe von strace)

Ich habe dies stattdessen verwendet, um Folgendes zu umgehen:

rm -r `find . -name dirname -type d`

Denken Sie daran, dass find weiterhin versucht, in Verzeichnisse mit dem Namen dirname zurückzukehren, was nicht unbedingt erforderlich ist und einige Zeit in Anspruch nimmt. Abhängig von Ihrer Verzeichnisstruktur können Sie dies möglicherweise mit der --depthSuchoption umgehen. Wenn Sie eine Verzeichnisstruktur wie dirname / foo / dirname haben, erhalten Sie außerdem die Fehlermeldung "Keine solchen Dateien oder Verzeichnisse" von rm. Um die Fehler zu unterdrücken, können Sie stderr nach / dev / null umleiten oder das -fFlag (force) mit rm verwenden.

Samuel
quelle
2
Schlechte Idee: Dateinamen mit Leerzeichen verursachen alle möglichen schrecklichen Probleme
Clément
2
Für zukünftige Leser: find . -name "to-delete" -print0 | xargs -r0 -- rm -rist eine ausfallsichere Version, die nicht auf Leerzeichen abstürzt
Charlie
3
Siehe unix.stackexchange.com/a/115869/8257, die Sie hinzufügen müssen -prune.
Mapio
1
Hinzufügen -prune, um den Fehler "Keine solche Datei oder Verzeichnis" zu vermeiden.
Julien Carsique
12

Ein schnellerer Weg, dies zu tun, ist:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

Falls Sie ".svn" in einer anderen ".svn" haben.

Chang Yu-heng
quelle
Dies ist nicht sehr nützlich, wenn Sie die zu löschenden Verzeichnisse in den Unterverzeichnissen suchen möchten.
Alexis Wilke
5

Bash-spezifische Lösung:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion
eilen
quelle
3
Hinweis: Bei der Befehlszeilenerweiterung von Globs, die mit vielen Dateien übereinstimmen, ist die Anzahl der Dateien, die mit diesem Mechanismus abgeglichen werden können, begrenzt. Going über diese Grenze führt inbash: /bin/rm: Argument list too long
DRAV Sloan
1
@DravSloan ist korrekt, aber dieses Limit liegt bei Hunderttausenden von Dateien. Es ist etwas zu beachten, aber wahrscheinlich wird es für die meisten Menschen kein Problem sein.
Evilsoup
4

Ich habe festgestellt, dass die -deleteAktion mit dem -pathTest gut funktioniert . Zum Beispiel sollte das folgende Problem mit den Originalplakaten gelöst werden:

find . -path '*/.svn*' -delete
Magnus
quelle
Bist du sicher? -deleteimpliziert -depth, und es löscht sicher nicht leere Verzeichnisse auf meinem System.
Magnus
Erneut getestet und es funktioniert. Vielleicht war es nur ein Tippfehler, den ich korrigiert habe.
Kenorb
Ich habe auch diesen Ansatz ausprobiert und es hat funktioniert - die Verzeichnisse wurden gelöscht.
Allan