Löschen Sie leere Unterordner, behalten Sie den übergeordneten Ordner bei

15

Wenn ich benutze

find /home/user/parentdir -type d -empty -delete

es sucht rekursiv nach leeren Unterordnern /home/user/parentdirund löscht sie. Wenn /home/user/parentdiraber auch leer ist, löscht es auch den parentdirOrdner, was für mich unerwünscht ist.

Ich möchte dies parentdirauf rsynceinige Dateien sichern oder Cloud. Nach der Verarbeitung muss ich die leeren Ordner löschen, aber es scheint unproduktiv, sie parentdirjedes Mal neu zu erstellen .

Irgendwelche Vorschläge zu behalten parentdir? Ich habe darüber nachgedacht, eine .nocopyDatei darin zu erstellen und diese auszuschließen rsync, aber es sieht aus wie ein Overkill. Gibt es einen eleganteren Weg?

TNT
quelle
Wenn Sie am Ende von / parentdir (dh / parentdir /) einen Schrägstrich / einfügen, macht das einen Unterschied?
Graham
6
-mindepth 1?
Steeldriver
@ Abraham / parentdir / löscht auch parentdir, macht also keinen Unterschied.
TNT
Ah, ich sehe, ich habe das * am Ende verpasst, das @ Amourk in seiner Antwort erwähnt.
Graham

Antworten:

25

Einfach machen find /home/user/parentdir -mindepth 1 -type d -empty -delete.

Aussehen:

$ mkdir -p test1/test2
$ find test1 -type d
test1
test1/test2
$ find test1 -mindepth 1  -type d
test1/test2

Die find /home/user/parentdir/* Antwort von in AmourK ist unerwünscht, wenn viele Dateien vorhanden und zu kompliziert sind.

chx
quelle
15

Indem Sie /*am Ende von hinzufügen parentdir, führen Sie die Aktion für alle Unterverzeichnisse von parentdir und nicht für sich parentdirselbst aus. Und so auf die gleiche Weise /home/user/nicht im alten Befehl gelöscht parentdirwird , wird nicht im folgenden Befehl gelöscht. *wird als Glob-Operator bezeichnet und entspricht einer beliebigen Zeichenfolge.

find /home/user/parentdir/* -type d -empty -delete

AmourK
quelle
7
Bei diesem Ansatz ist zu beachten , dass der erweiterte Glob bei einer großen Anzahl von Dateien /home/user/parentdir/möglicherweise überschritten wird ARG_MAX, was zu einem zu langen Fehler in der Argumentliste führt. Sie können das Risiko verringern, indem Sie den Glob */so ändern, dass er nur mit Verzeichnissen übereinstimmt.
Steeldriver
12
Achten Sie auch darauf, dass keine Kinder gefunden werden, die mit einem Punkt beginnen. Und eines Tages werden Sie dies bemerken, und wenn Sie auch nach ". *" Suchen, werden Sie in einer riesigen Welt voller Verletzungen sein (weil ". *" Mit ".." übereinstimmt). Frag mich, woher ich das weiß.
Glenn Willen
1
@GlennWillen, warum denke ich, sollten wir mit Getränken vor uns an einer Bar sitzen, bevor ich dich bitte, diese Geschichte zu erzählen?
Monty Harder
@MontyHarder Zum Glück war es nicht so schlimm, wie es hätte sein können. Es befand sich auf meinem ersten Unix-System, einer Solaris-Maschine, die meiner Highschool gehörte. Gott sei Dank lief ich nicht "rm", sondern "chown". Ich habe mit root versucht, die Inhaberschaft für alles in meinem Ausgangsverzeichnis zu reparieren. Stattdessen habe ich mir JEDES Homeverzeichnis (und alle Inhalte) zu eigen gemacht und musste sie dann alle zurücksetzen.
Glenn Willen
Ich hatte einen Mitarbeiter, der einen neuen Mitarbeiter darin schulte, wie man eine Software installiert. Es ging darum /tmp, ein Unterverzeichnis zu erstellen, dort einen komprimierten Tarball zu entpacken, das Installationsprogramm auszuführen und aufzuräumen. Der Neuling dachte, das rm -rf /tmp/foo-installsei der richtige Weg, und wie die erfahrene Hand in seinem besten Darth-Vader-am-Ende-der-Episode-III-Eindruck "Noooooo" sagte, fand der Neuling auf die harte Tour heraus, wie nahe das ist / und Enter-Tasten waren zueinander. Wir mussten von der Wiederherstellungsdiskette der Sicherungssoftware booten und den gesamten Server von Band neu laden.
Monty Harder
0

wenn du php-cli installiert hast,

printf %s $(pwd) | php -r 'function f(string $dir){var_dump($dir);$dir.=DIRECTORY_SEPARATOR;foreach(glob("$dir*",GLOB_ONLYDIR) as $d){f($d);}global $original;if(substr($dir,0,-strlen(DIRECTORY_SEPARATOR))!==$original && empty(glob("$dir*"))){rmdir($dir);}}f(($original=stream_get_contents(STDIN)));'
Hanshenrik
quelle
Sie wollten foreach (RecursiveIteratorIterator(RecursiveDirectoryIterator($dir)) as $p) if (empty($skipped)) $skipped = TRUE; elseif ($p->isDir()) @rmdir($p->getPathname());oder etwas in der Nähe. $skippedkümmert sich um das Überspringen des ersten Verzeichnisses, @rmdirversucht, ein Verzeichnis zu entfernen, und schlägt stumm (das ist das @) fehl, wenn es nicht leer ist.
CHX
0

Wenn Sie nur eine Ebene benötigen (einen übergeordneten Ordner verlassen, aber leere untergeordnete Ordner löschen), können Sie dies ganz einfach tun rmdir.

rmdir parent/*

Löscht alle leeren Unterordner, druckt jedoch nur einen Fehler für Dateien und nicht leere Ordner.

Dies funktioniert nicht rekursiv, aber wenn Sie Ihre Ordnerstruktur kennen, ist dies möglicherweise der schnellste Weg, um so etwas zu tun

rmdir parent/*/*/* # deletes parent/a/b/c when empty
rmdir parent/*/* # deletes parent/a/b when it is now empty
rmdir parent/* # deletes parent/a when it is now empty

Vorteil: Einfach zu merken, schnell zu tippen, wenig Potenzial für die Wahl eines falschen Parameters.
Nachteil: Weniger flexibel, möglicherweise viele Fehlermeldungen in Ihrem Terminal.

allo
quelle