Leere Verzeichnisbäume entfernen (so viele Verzeichnisse wie möglich, aber keine Dateien entfernen)

12

Angenommen, ich habe einen Verzeichnisbaum wie diesen:

ROOTDIR
    └--SUBDIR1
        └----SUBDIR2
            └----SUBDIR3

Ich suche nach einem solchen Befehl, dass bei der Eingabe:

$ [unknown command] ROOTDIR

Der gesamte Verzeichnisbaum kann gelöscht werden, wenn keine Datei vorhanden ist, sondern nur Verzeichnisse innerhalb des gesamten Verzeichnisbaums . Sagen Sie jedoch, ob es unter SUBDIR1 eine Datei namens hello.pdf gibt:

ROOTDIR
    └--SUBDIR1
        └--hello.pdf
        └----SUBDIR2
            └----SUBDIR3

Dann darf der Befehl nur SUBDIR2 und darunter löschen.

gsklee
quelle
Dies scheint ein Duplikat von Wie entferne
David Cary

Antworten:

11

Alexis ist in der Nähe. Was Sie tun müssen, ist Folgendes:

find . -type d -depth -empty -exec rmdir "{}" \;

Dadurch wird zuerst der Verzeichnisbaum durchsucht, bis das erste leere Verzeichnis gefunden und dann gelöscht wird. Dadurch wird das übergeordnete Verzeichnis leer, das dann gelöscht wird, usw. Dies erzeugt den gewünschten Effekt (ich mache dies wahrscheinlich 10 Mal pro Woche, also bin ich mir ziemlich sicher, dass es richtig ist). :-)

Steve Juranich
quelle
Warum ist eine -depthOption notwendig? find . -type d -empty -exec rmdir "{}" \;sollte auch funktionieren .... oder?
Abhishek A
4
Überlegen Sie, ob Sie einen Baum haben (nur Verzeichnisse) foo/bar/baz. Wenn Sie dies nicht verwenden -depth, wird zuerst versucht, zu löschen. Wenn dies foofehlschlägt, wird das Programm foo/barausgeführt.
l0b0
1
Möglicherweise Alternative ist die Verwendung +statt , ;so dass Sie Batch entfernen Verzeichnisse. Da Sie dies zuerst tun, werden die Kinder vor den Eltern entfernt (möglicherweise abhängig von Ihrer Version von rmdir / bash und abhängig davon, dass rmdir keine nicht leeren Verzeichnisse löscht). Dies funktioniert für mich in Bash auf Cygwin:mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} +
Idbrii
3
Leute, sucht die viel prägnantere Antwort von go2null! Kann nicht verstehen, warum SE akzeptierten Antworten Vorrang einräumt, anstatt Antworten mit den meisten positiven Stimmen, wenn die Antworten unter der Frage angezeigt werden. Das OP akzeptiert die beste Antwort, die zur Zeit seiner Wahl verfügbar war, aber später können viel bessere Antworten kommen, die von der Community positiv bewertet werden. Nein? (Natürlich ist dies etwas für Meta ...)
Jamadagni
das funktioniert bei mir nicht es löscht nur das tiefste Blatt (in diesem Fall
SUBDIR3
23
find ROOTDIR -type d -empty -delete

gleich wie

find ROOTDIR -type d -depth -empty -exec rmdir "{}" \;

benutzt aber die eingebaute "-delete" Aktion.

Beachten Sie, dass "-delete" "-depth" impliziert.

go2null
quelle
Ein dickes Lob für die prägnanteste Antwort mit der integrierten Funktion "Löschen" von find! Ich füge dies meinen lokalen utilscripts hinzu!
Jamadagni
3

Ich würde Folgendes versuchen:

find ROOTDIR -type d -depth -exec rmdir {} \;
Alexis
quelle
1

Hier sind einige Voraussetzungen, bevor wir es sicher machen können:

  1. entfernen Sie zuerst die Unterverzeichnisse und dann die übergeordneten Verzeichnisse, dh Sie müssen die Verzeichnisliste sortieren oder das Flag rmdir --parents verwenden
  2. Starten Sie ROOTDIR immer mit / oder ./, um Überraschungen bei Dateien zu vermeiden, die mit - beginnen.
  3. Verwenden Sie die NUL-terminierte Verzeichnisliste, um mit Verzeichnisnamen mit Leerzeichen zu arbeiten

So würde ich das in der Shell machen:

find ./ROOTDIR -type d | sort -r | tr '\n' '\000' | xargs -0 rmdir --ignore-fail-on-non-empty

Wenn Sie nichts gegen überflüssige Fehler haben, können Sie das Entfernen aller Verzeichnisse mit übergeordneten Elementen erzwingen und müssen keine Sortierung vornehmen (Sie können keine mit NUL abgeschlossenen Zeichenfolgen sortieren, die tr hinzufügen müssen).

find ./ROOTDIR -type d -print0 | xargs -0 rmdir --ignore-fail-on-non-empty --parents
Puma
quelle
Ein dickes Lob für die ausführliche Erklärung Ihrer Antwort. Ich hätte wahrscheinlich den gleichen Ansatz gewählt, bis ich -empty -deleteOptionen für finddie Antwort von @ go2null kennengelernt habe.
Davor Cubranic
0
rmdir $(find ROOTDIR -type d | sort -r)
lanzz
quelle
5
Dies funktioniert nicht, wenn einer der Verzeichnisnamen Whitespace- oder Globbing-Zeichen enthält. Es ist im Allgemeinen eine schlechte Idee, die Befehlsersetzung für eine Liste von Dateinamen zu verwenden. Es ist vor allem eine schlechte Idee , mit findda findhat eine Art , die Verarbeitung sauber zu tun: find … -exec.
Gilles 'SO - hör auf böse zu sein'
Vielen Dank an Gilles für diesen Hinweis. @lanzz, normalerweise ist es nicht ausreichend, nur einen Befehl zu veröffentlichen, ohne zu erklären, was er tut (und in diesem Fall die Fallstricke). Bitte ergänzen Sie Ihre Antwort.
8.
0

Ich würde das machen:

find ROOTDIR -type d | xargs -0 -I {} rmdir {}
Chemila
quelle