Wie entferne ich alle Unterverzeichnisse innerhalb eines Verzeichnisses?

51

Diese Frage ist eine Art Phase II der ersten Frage, die ich hier gestellt habe

Ich habe ein Verzeichnis, das eine Reihe von Unterverzeichnissen, ZIP-Dateien und anderen zufälligen Dateien enthält, die nicht in einem Unterverzeichnis enthalten sind.

Ich möchte ein Befehlszeilenskript, um alle Unterverzeichnisse aus dem übergeordneten Verzeichnis zu entfernen, aber alle ZIP-Dateien und losen Dateien, die zu keinen Unterverzeichnissen gehören, beizubehalten. Alle Unterverzeichnisse haben Inhalt, daher glaube ich, dass ich das Löschen mit dem Befehl -f erzwingen muss.

Im Grunde genommen löscht ein Befehl, der sich im übergeordneten Verzeichnis (oder im aktuellen Verzeichnis) befindet, alle darin enthaltenen Ordner, behält jedoch alle anderen Inhalte und Dateien bei, die kein Ordner sind oder in einem Ordner enthalten sind.

Ich verstehe, dass das Löschen von Elementen über die Befehlszeile besondere Sorgfalt erfordert, aber ich habe bereits alle erforderlichen Vorkehrungen getroffen, um eine Remote-Sicherung durchzuführen.

Evster
quelle

Antworten:

61

In BASH können Sie den abschließenden Schrägstrich verwenden (ich denke, er sollte in jeder POSIX-Shell funktionieren):

rm -R -- */

Beachten Sie, --dass Optionen von Argumenten getrennt werden und Einträge entfernt werden können, die mit einem Bindestrich beginnen. Andernfalls wird der Eintragsname nach der Erweiterung durch die Shell als Option von interpretiert rm(dies gilt auch für viele andere Befehlszeilenprogramme).

Fügen Sie die -fOption hinzu, wenn Sie beim Löschen von nicht beschreibbaren Dateien nicht zur Bestätigung aufgefordert werden möchten.

Beachten Sie, dass versteckte Verzeichnisse (Verzeichnisse, deren Name mit "" beginnt .) standardmäßig in Ruhe gelassen werden.

Eine wichtige Einschränkung: Die Erweiterung von */wird auch Symlinks enthalten, die schließlich in Dateien vom Typ Verzeichnis aufgelöst werden . Und je nach rmImplementierung rm -R -- thelink/wird entweder nur der Symlink oder (in den meisten Fällen) der Inhalt des verknüpften Verzeichnisses rekursiv gelöscht , nicht jedoch das Verzeichnis selbst oder der Symlink.

In zshdiesem Fall wäre es besser, ein Glob-Qualifikationsmerkmal zu verwenden, um nur Dateien vom Typ directory auszuwählen:

rm -R -- *(/) # or *(D/) to include hidden ones

oder:

rm -R -- *(-/)

Einfügen von Symlinks zu Verzeichnissen (da die Erweiterung diesmal keine nachgestellten /s enthält, wird nur der Symlink bei allen rmImplementierungen entfernt).

Mit bashAT & T ksh, yashoder zshSie tun können:

set -- */
rm -R -- "${@%/}"

das Schleppen abziehen /.

peterph
quelle
Schön! Das funktioniert einwandfrei. Mir war nicht klar, dass es so einfach ist. Würde es Ihnen etwas ausmachen, das -r vs. -R auszuarbeiten und was diese Befehle bewirken? Danke vielmals.
Evster
-r, -R, --recursiveSind Synonyme „entfernen Verzeichnisse und deren Inhalt rekursiv“ bedeutet.
Peterph
kannst du erklären was - und * / tun?
Amphibient
6
Sie können auch sagen rm -R ./*/- Es vermeidet auch Probleme mit Bindestrichnamen.
l0b0
1
Achten Sie nur darauf, die Reihenfolge von * und / nicht zu ändern. rm -R - / * macht etwas völlig anderes, was Sie vielleicht nicht wollen: |
ChrisOdney
13

Zusätzlich zum Wildcard-Weg können Sie auch find(mindestens GNU find) verwenden, um dies zu tun:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 rm -R

Wie bei anderen findZeilen können Sie den ersten Teil ( find -mindepth 1 -maxdepth 1 -type d) ausführen , um eine Liste der zu entfernenden Verzeichnisse anzuzeigen.

Eine sicherere Option besteht darin, Folgendes zu tun:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 mv -i -t ../to-rm
# or
mv -i -t ../to-rm */
# or
mv -i */ ../to-rm

Jedes davon verschiebt das gesamte Material, ../to-rmanstatt es zu löschen. Sie können überprüfen, ob es getan hat, was Sie wollten, indem Sie rm -Rfdas Verzeichnis nach Belieben auswählen.

derobert
quelle
+1 für den „CLI-Papierkorb“ to-rmund findder gut behandelt Verzeichnisse mit einem Punkt (zusätzlich zu allen anderen umständlich escaping) beginnen. :)
Peterph
Danke für den Tipp. Ich mag die Idee, vor dem Löschen in ein separates Verzeichnis zu wechseln. Ich arbeite über Terminal unter Mac OS X und ich glaube, ich muss eine Art GNU-Paket installieren, um die Befehle -mindepth und -maxdepth zu verwenden, richtig?
Evster
@Evster ist sich nicht sicher, ob Mac OS X diese unterstützt. Ich würde vermuten, Fink (ist das noch da?) Könnte einen Fund installieren, der das tut. Oder Sie können sie weglassen und dann die erzeugte Dateiliste mit grep filtern. Verwenden Sie auf jeden Fall die Option mv anstelle von rm.
Derobert
4

Möglicherweise möchten Sie insbesondere für einige dieser Vorschläge ein Skript erstellen rm -R -- */und in Ihrem Ordner / usr / local / bin aufbewahren. oder erstellen Sie eine aliasin Ihrer ~ / .bashrc-Datei. Da es so einfach ist, einen Befehl falsch einzugeben und Ihr System zu beschädigen - selbst ein einzelner Buchstabe und / oder die Reihenfolge der Buchstaben können katastrophale Folgen haben -, wäre dies eine etwas robustere Lösung, als die verschiedenen Optionen und Argumente eingeben zu müssen jedes Mal, wenn Sie diese Aufgabe ausführen möchten.

Möglicherweise möchten Sie Ihrem Skript / Befehl auch die Option -i or --interactive=onceoder -I or --interactive=alwayshinzufügen, die als weiteres Werkzeug dient, um unbeabsichtigte Löschvorgänge zu vermeiden.

Darüber hinaus wäre etwas wie derobert vorgeschlagen am besten; Kopieren Sie das Skript einfach in einen Datei- / Terminal-Editor und passen Sie es an Ihre spezifischen Bedürfnisse an. Die Dateien / Verzeichnisse werden in ein einzelnes Verzeichnis verschoben (dessen Inhalt Sie überprüfen / verifizieren können), das Sie einfach entfernen können Ausgabe des rm -rfBefehls.

Eine andere Möglichkeit besteht darin, eine GUI-Anwendung wie Ihren Dateimanager zu verwenden und einfach alle zutreffenden Dateien / Ordner auszuwählen, die Sie löschen möchten. Überprüfen Sie die Handbuchseiten Ihrer Distribution, wenn Sie keine Berechtigungen haben.

Wenn die Ordner leer sind - im Wesentlichen einfache Dateinamen -, können Sie sie mit dem rmdirBefehl löschen. Es funktioniert nicht für alles, was Sie löschen möchten, aber es wird sich als nützlich erweisen, wenn Sie eine "Hausreinigung" durchführen möchten. ** Möglicherweise möchten Sie die -p --ignore-fail-on-non-emptyOption ausprobieren , mit der Sie bestimmte Unterverzeichnisse sowie deren leere "Eltern" - die Verzeichnisse, in denen sie sich befinden - löschen können.

ILMostro_7
quelle
Das ist eine wirklich gute Idee, ein separates Skript zu erstellen, das ich für diesen Befehl aufrufen kann. Können Sie erklären, was genau die Optionen -i und -I bewirken? Vielen Dank!
Evster
-Ich werde Sie nach dem Drücken der Eingabetaste einmal zur Bestätigung auffordern, dass Sie dies entfernen möchten (wenn mehr als 3 Dateien / Ordner "ausgewählt" sind). Während die Option -i eine Eingabeaufforderung für jede Datei ausgibt, bei der Sie einfach durch Tippen auf "y" und "Enter" bestätigen können, führt eine andere als positive Antwort dazu, dass diese bestimmte Datei während des Entfernungsvorgangs übersprungen wird.
ILMostro_7
1

Zuerst müssen Sie die Verzeichnisse auflisten und dann entfernen, ohne die normalen Dateien zu beeinträchtigen. Ls -d * / listet nur die Unterverzeichnisse auf, und wenn Sie es mit rm weiterleiten, werden die Verzeichnisse und Inhalte entfernt, wobei die losen Dateien intakt bleiben.

Dieser Befehl sollte die Arbeit erledigen,

ls -d  */ | xargs rm -rf
Ankit Marothi
quelle
1
Was wäre der Vorteil gegenüber rm -rf -- */? printf '%s\0' */ | xargs -r0 rm -rf --würde helfen (in Shells, wo printfes eingebaut ist und nicht ls), um zu große Fehler in der ls -d */ | xargs rm -rfArg- Liste zu umgehen, füge aber nichts AFAICT hinzu, außer zusätzliche Probleme.
Stéphane Chazelas
1
@AnthonyGeoghegan, ja, wenn beispielsweise ein Verzeichnis mit dem Namen " .."(Leerzeichen ..) vorhanden ist, wird bei einigen lsImplementierungen der Inhalt des übergeordneten Verzeichnisses entfernt . Und es sind nicht nur Leerzeichen, sondern auch andere Leerzeichen, Zeilenumbrüche, einfache Anführungszeichen, doppelte Anführungszeichen, umgekehrte Schrägstriche und Dateinamen, die mit beginnen -.
Stéphane Chazelas
2
@Ankit, Sie könnten mit mywiki.wooledge.org/ParsingLs
Stéphane Chazelas
1
Wenn Sie den Vorschlag von @ StéphaneChazelas, printfeine Liste zu erstellen, xargsbei der jeder Name mit dem Null-Zeichen abgeschlossen ist, damit er mit der -0Option verarbeitet werden kann, vollständig verstanden haben , sollten Sie Ihre Antwort bearbeiten , um sie mit seiner Variation zu aktualisieren. Ich bin mir ziemlich sicher, dass er sich freuen würde, wenn Sie sein Code-Snippet verwenden, wenn Sie es verstehen und wissen, wie es vor unerwünschtem Verhalten schützt, das durch bestimmte möglicherweise vorhandene Dateinamen verursacht wird.
Anthony G - Gerechtigkeit für Monica
1
Die Verwendung xargshat einen Vorteil gegenüber der akzeptierten Antwort (sie funktioniert, wenn das aktuelle Verzeichnis eine sehr große Anzahl von Dateien / Verzeichnissen enthält), sodass Sie diese in eine nützliche Antwort umwandeln können. Persönlich habe ich festgestellt, dass das Beantworten von Stack Exchange- Fragen eine gute Lernerfahrung ist - insbesondere, wenn ich nützliche Rückmeldungen von anderen Benutzern erhalte.
Anthony G - Gerechtigkeit für Monica
-1

rm -rf <directory name>. Es klappt. Das bloße Tippen rm <directory name>führt nur zu einer Reihe von Unterfragen, in denen jedes Unterverzeichnis manuell entfernt werden muss. Aber rm -rfhilft das ganze Verzeichnis zusammen mit seinen Unterverzeichnissen auf einmal zu entfernen.

Riya Melvin
quelle
5
Das OP bat darum, den Inhalt des aktuellen Verzeichnisses beizubehalten.
Stephen Rauch