Supprimer les sous-dossiers vides, conserver le dossier parent

15

Quand j'utilise

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

il recherche récursivement les sous-dossiers vides à l'intérieur /home/user/parentdiret les supprime. Mais s'il /home/user/parentdirest également vide, il supprime également le parentdirdossier, ce qui n'est pas souhaitable pour moi.

Je souhaite conserver cela parentdirdans rsynccertains fichiers à sauvegarder ou dans le cloud. Après le traitement, je dois supprimer les dossiers vides, mais semble improductif à recréer à parentdirchaque fois.

Des suggestions à garder parentdir? J'ai pensé à créer un .nocopyfichier à l'intérieur et à l'exclure rsync, mais cela semble exagéré. Existe-t-il une manière plus élégante?

TNT
la source
si vous ajoutez une barre oblique / à la fin de / parentdir (c'est-à-dire / parentdir /) cela fait-il une différence?
Graham
6
-mindepth 1?
steeldriver
@Graham / parentdir / supprime également parentdir, donc cela ne fait aucune différence.
TNT
ah, je vois que j'ai raté le * à la fin que @Amourk mentionne dans sa réponse.
Graham

Réponses:

25

Faites-le simplement find /home/user/parentdir -mindepth 1 -type d -empty -delete.

Regardez:

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

La find /home/user/parentdir/* réponse d'AmourK n'est pas souhaitable lorsqu'il y a beaucoup de fichiers et qu'elle est trop compliquée.

chx
la source
15

En ajoutant /*à la fin de parentdir, vous effectuez l'action sur tous les sous-répertoires de parentdir plutôt que sur parentdirlui-même. Et donc de la même manière /home/user/n'est pas supprimé dans l'ancienne commande, parentdirne sera pas supprimé dans la commande ci-dessous. *est appelé un opérateur glob et il correspond à n'importe quelle chaîne de caractères.

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

AmourK
la source
7
Une chose à savoir avec cette approche est que s'il y a un grand nombre de fichiers /home/user/parentdir/, le glob étendu peut dépasser ARG_MAX, ce qui entraîne une liste d'arguments trop longue . Vous pouvez réduire le risque que cela se produise en modifiant le glob pour */qu'il corresponde uniquement aux répertoires.
steeldriver
12
Sachez également que cela ne trouvera aucun enfant commençant par un point. Et un jour, vous vous en rendrez compte et si vous faites également une recherche pour ". *", Vous serez dans un immense monde de blessures (parce que ". *" Correspond à ".."). Demandez-moi comment je sais.
Glenn Willen
1
@GlennWillen pourquoi je pense que nous devrions être assis dans un bar avec des boissons devant nous avant de vous demander de raconter cette histoire?
Monty Harder
@MontyHarder Ce n'était heureusement pas aussi mauvais qu'il aurait pu l'être. C'était sur mon premier système Unix, qui était une machine Solaris appartenant à mon lycée. Dieu merci, je n'exécutais pas «rm», mais plutôt «chown». J'utilisais root pour essayer de corriger la propriété de tout dans mon répertoire personnel. Au lieu de cela, je me suis donné la propriété de CHAQUE répertoire personnel (et de tout leur contenu), puis j'ai dû les remettre tous.
Glenn Willen
Un collègue a formé un nouvel employé à l'installation d'un logiciel. Cela impliquait d'aller /tmp, de créer un sous-répertoire, de décompresser une archive tar compressée, d'exécuter le programme d'installation et de nettoyer. Le débutant pensait que rm -rf /tmp/foo-installc'était la bonne façon de le faire, et comme la main expérimentée a dit "Noooooo" dans sa meilleure impression de Dark-Vader-à-la-fin-de-l'épisode-III, le newb a découvert à la dure à quel point le / et les touches Entrée étaient l'une pour l'autre. Nous avons dû démarrer à partir du disque de restauration du logiciel de sauvegarde et recharger l'ensemble du serveur à partir de la bande.
Monty Harder
0

si vous avez installé php-cli,

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
la source
vous vouliez foreach (RecursiveIteratorIterator(RecursiveDirectoryIterator($dir)) as $p) if (empty($skipped)) $skipped = TRUE; elseif ($p->isDir()) @rmdir($p->getPathname());ou quelque chose de proche. $skippeds'occupe de sauter le premier, @rmdiressaie de supprimer un répertoire et silencieusement (c'est le @) échoue s'il n'est pas vide.
chx
0

Lorsque vous n'avez besoin que d'un seul niveau (quitter un dossier parent, mais supprimer des dossiers enfants vides), une astuce simple consiste à utiliser rmdir.

rmdir parent/*

Supprime tous les sous-dossiers vides, mais imprime uniquement une erreur pour les fichiers et les dossiers non vides.

Cela ne fonctionne pas récursivement, mais lorsque vous connaissez la structure de votre dossier, cela peut être le moyen le plus rapide de faire quelque chose comme

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

Avantage: facile à mémoriser, rapide à taper, peu de potentiel pour choisir un mauvais paramètre.
Inconvénient: moins flexible, peut-être beaucoup de messages d'erreur dans votre terminal.

allo
la source