Supprimer les arborescences de répertoires vides (supprimer autant de répertoires que possible mais pas de fichiers)

12

Supposons que j'ai un arbre dir comme celui-ci:

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

Je recherche une commande telle que lorsque j'entre:

$ [unknown command] ROOTDIR

L'arborescence de répertoires entière peut être supprimée s'il n'y a pas de fichier mais uniquement des répertoires à l'intérieur de l'arborescence entière . Cependant, dites s'il y a un fichier appelé hello.pdf sous SUBDIR1:

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

Ensuite, la commande doit uniquement supprimer SUBDIR2 et inférieur.

gsklee
la source
Cela semble être un doublon de Comment supprimer tous les répertoires vides dans un sous-arbre?
David Cary

Réponses:

11

Alexis est proche. Ce que vous devez faire est le suivant:

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

Cela va d'abord explorer l'arborescence des répertoires jusqu'à ce qu'il trouve le premier répertoire vide, puis le supprimer. Rendre ainsi le répertoire parent vide qui sera ensuite supprimé, etc. Cela produira l'effet souhaité (je le fais probablement 10 fois par semaine, donc je suis sûr que c'est vrai). :-)

Steve Juranich
la source
Pourquoi l' -depthoption est-elle nécessaire? find . -type d -empty -exec rmdir "{}" \;devrait également fonctionner .... non?
Abhishek A
4
Considérez si vous avez une arborescence (répertoires uniquement) foo/bar/baz. À moins que vous n'utilisiez -depth, il essaiera de supprimer d' fooabord, échouera et vous vous retrouverez avec foo/baraprès avoir exécuté.
l0b0
1
Une alternative possible est d'utiliser à la +place de ;si vous supprimez des répertoires par lots. Puisque vous le faites en profondeur d'abord, les enfants seront toujours supprimés avant les parents (éventuellement dépendants de votre version de rmdir / bash et dépendants de rmdir ne supprimant pas les répertoires non vides). Cela fonctionne pour moi dans bash sur cygwin:mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} +
idbrii
3
Les gens, optez pour la réponse beaucoup plus succincte de go2null ci-dessous! Je ne comprends pas pourquoi SE accorde la priorité aux réponses acceptées plutôt qu'aux réponses avec la plupart des votes positifs en affichant les réponses sous la question. Le PO accepte la meilleure réponse disponible au moment de son choix, mais par la suite, de bien meilleures réponses peuvent arriver, que la communauté vote positivement, non? (Bien sûr, c'est quelque chose pour la méta ...)
jamadagni
Cela ne fonctionne pas pour moi. il supprime seulement la feuille la plus profonde (SUBDIR3 dans ce cas)
Joey Baruch
23
find ROOTDIR -type d -empty -delete

pareil que

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

mais utilise l'action intégrée "-delete".

Notez que "-delete" implique "-depth".

go2null
la source
Bravo pour la réponse la plus succincte en utilisant la propre suppression intégrée de find! J'ajoute ceci à mes scripts locaux!
jamadagni
3

J'essaierais ceci:

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

Voici quelques exigences avant de pouvoir le faire en toute sécurité:

  1. supprimer d'abord les sous-répertoires, puis les répertoires de niveau supérieur, c'est-à-dire que nous devons trier la liste des répertoires ou utiliser l'indicateur rmdir --parents
  2. démarrer ROOTDIR toujours avec / ou ./ pour éviter les surprises avec les fichiers commençant par -
  3. utiliser une liste de répertoires terminée par NUL pour travailler avec des noms de répertoire avec des espaces

Voici comment je ferais cela en shell:

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

Si cela ne vous dérange pas certaines erreurs redondantes, vous pouvez simplement forcer la suppression de tous les répertoires avec les parents et vous n'avez pas besoin de faire de tri (vous ne pouvez pas trier les chaînes terminées par NUL, ce qui ajoute la nécessité de tr)

find ./ROOTDIR -type d -print0 | xargs -0 rmdir --ignore-fail-on-non-empty --parents
Puma
la source
Bravo pour l'explication détaillée de votre réponse. J'aurais probablement utilisé la même approche jusqu'à ce que j'apprenne les -empty -deleteoptions finddans la réponse de @ go2null.
Davor Cubranic
0
rmdir $(find ROOTDIR -type d | sort -r)
lanzz
la source
5
Cela ne fonctionnera pas si l'un des noms de répertoire contient des espaces ou des caractères globbing. C'est généralement une mauvaise idée d'utiliser la substitution de commandes sur une liste de noms de fichiers. Il est particulièrement une mauvaise idée avec findparce que finda une façon de faire le traitement proprement: find … -exec.
Gilles 'SO- arrête d'être méchant'
Merci à Gilles de l'avoir signalé. @lanzz, généralement afficher juste une commande sans expliquer ce qu'elle fait (et dans ce cas, les pièges) n'est pas suffisant. Veuillez ajouter à votre réponse.
n0pe
0

Je ferais ceci:

find ROOTDIR -type d | xargs -0 -I {} rmdir {}
chemila
la source