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.


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). :-)


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".


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 {} \;

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

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)

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 {}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.