Ich habe einige Ordner mit \n
Charakter, deren Namen.
zum Beispiel:
$ ls
''$'\n''Test'
Das bezieht sich auf einen Ordner mit einem Testnamen und einer Leerzeile vor seinem Namen.
Wenn ich also einige Skripte wie dieses im übergeordneten Verzeichnis ausführe:
while IFS= read -r d; do
rmdir $d
done < <(find * -type d)
Es zeigt:
rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Weil es zweimal ausgeführt wird, einmal \n
und einmal Test
, weil der Ordnername zwei Zeilen hat.
Wie kann ich dieses Problem so lösen, dass das Skript \nTest
nur einen Ordner kennt ?
command-line
bash
scripts
Tara S Volpe
quelle
quelle
-print0
Direktive von find und die-d
Leseoption verwenden. Siehe stackoverflow.com/a/40189667/7552find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done
Befehl haben diese Ausgabermdir: failed to remove 'Test': No such file or directory
.rmdir "$file"
Antworten:
Sie haben dort nur einen einzigen Befehl, daher reicht es aus,
find
mit einem-exec
Flag-Aufruf aufzurufenrmdir
:Oder verwenden Sie die
-delete
Option wie infind -type d -delete
, sie funktioniert jedoch nicht mit nicht leeren Verzeichnissen. Dafür benötigen Sie auch-empty
Flagge. Beachten Sie auch,-delete
impliziert ,-depth
so dass übersprungenen sein kann. Eine weitere Alternative, die alles als einen Prozess betrachtet:Wenn das Verzeichnis nicht leer ist, verwenden Sie
rm -rf {} \;
. Um nur Verzeichnisse mit dem\n
Dateinamen zu isolieren, können wir das ANSI-C-Zitat von bash$'...'
mit-name
opption kombinieren:POSIX-ly, wir könnten so umgehen:
Es ist erwähnenswert, dass, wenn Ihr Ziel das Entfernen von Verzeichnissen
-delete
ist, dies ausreicht. Wenn Sie jedoch einen Befehl für ein Verzeichnis ausführen möchten,-exec
ist dies am besten geeignet.Siehe auch
find
Ausgabe?quelle
rm -rf
Vorsichtig verwenden . ; P Hat nichtfind
eine haben-delete
btw Option? Es löscht leere Verzeichnisse und wirft Fehler für nicht leere wiermdir
- möglicherweise günstiger.-delete
nicht leere Verzeichnisse werden nicht entfernt. Daher die sorgfältige Verwendung vonrm -rf
find
Befehle ohne destruktive Nutzlast (dh entfernen Sie den-delete
oder-exec whatever \;
) zu überprüfen , ob die Liste der betroffenen Dateien tatsächlich korrekt ist , und enthält keine Sachen , die nicht gelöscht werden sollte ...find
. Verwenden Sie-exec rmdir {} +
diese Option, um mehrere Argumente auf einerrmdir
Befehlszeile zu stapeln. Und übrigens " aber es funktioniert nicht mit nicht leeren Verzeichnissen. " Giltrmdir
auch für, also ist das eigentlich kein Unterschied zu-delete
. Es ist ein Unterschied zurm -r
.find -type d -empty -delete
(-delete
impliziert-depth
).Sie könnten Shell Globs anstelle von verwenden
find
:Der Shell-Glob
*/
entspricht allen Ordnern im aktuellen Verzeichnis. Diese For-Loop-Konstruktion sorgt automatisch für die korrekte Wortteilung.Beachten Sie, dass abhängig von Ihren Shell-Optionen möglicherweise versteckte Ordner ignoriert werden (Name beginnt mit a.). Dieses Verhalten kann mit dem Befehl so geändert werden, dass alle Dateien für die aktuelle Sitzung übereinstimmen
shopt -s dotglob
.Vergessen Sie auch nicht, immer Ihre Variablen anzugeben.
quelle
find
tutshopt -s globstar
und stattdessen ein**/*/
Glob verwendet wird.Beide bisher geschriebenen Antworten werden
rmdir
einmal pro Verzeichnis aufgerufen , aber darmdir
ich mehrere Argumente annehmen kann, frage ich mich: Gibt es keinen effizienteren Weg?Man könnte es einfach tun
und das ist definitiv der einfachste und effizienteste Weg, aber es kann bei vielen Verzeichnissen einen Fehler auslösen (siehe Was ist die maximale Länge von Befehlszeilenargumenten in gnome-terminal? ). Wenn dieser Ansatz rekursiv funktionieren soll, aktivieren Sie die
globstar
Shell-Option mitshopt -s globstar
und verwenden Sie**/*/
statt*/
.Mit GNU
find
(und wenn wir nicht nur verwenden wollen-delete
) könnten wir es tunDadurch wird die Befehlszeile "ähnlich wie die
xargs
Befehlszeilen" erstellt (man find
). Ersatz-depth
für ,-maxdepth 1
wenn Sie nicht wollen , es rekursiv zu arbeiten.Ein dritter und IMO brillanter Weg wird von steeldriver in dieser Antwort erklärt :
Dies verwendet die eingebaute Shell
printf
, um eine durch Null getrennte Argumentliste zu erstellen. Diese Liste wird dann weitergeleitet, anxargs
diermdir
genau so oft wie nötig aufgerufen wird . Sie können dafür sorgen, dass es rekursiv mitshopt -s globstar
und**/*/
statt*/
wie oben beschrieben funktioniert .quelle
find
ist rekursiv, die Schleife des OP jedoch nicht. Verwenden Sie, um dieses Verhalten zu replizierenfind -maxdepth 1 -type d -exec rmdir {} +
. (-depth
ist in diesem Fall überflüssig.) Ordentlicher Trickprintf
zum Emulierenfind -print0
, das hatte ich vorher noch nicht gesehen.ls
und diewhile
Schleife gesehen und habe übersehen, dass sie von einer Prozessersetzung mit umgeleitet wurden,find
anstattls
in die Schleife zu leiten und sie aus irgendeinem Grund nicht anzuzeigen. Dasfind *
ist wirklich begraben. Ja, es ist rekursiv und schlägt fehl, wenn das Verzeichnis zu viele Verzeichniseinträge enthält, einschließlich Nicht-Verzeichnisse, da es nicht verwendet wird*/
.find .
wäre viel besser, weilfind
es schneller iststat
als die Glob-Expansion von Bash.