Comment supprimer tous les sous-répertoires d'un répertoire?

51

Cette question est une sorte de phase II à la première question que j'ai posée ici

J'ai un répertoire qui contient un tas de sous-répertoires, fichiers .zip et autres fichiers aléatoires non contenus dans un sous-répertoire.

J'aimerais qu'un script de ligne de commande supprime tous les sous-répertoires du répertoire parent, mais conserve tous les fichiers zip et les fichiers en vrac qui n'appartiennent à aucun sous-répertoire. Tous les sous-répertoires ont un contenu, je pense donc que je devrais forcer leur suppression avec la commande -f.

Donc, en gros, une commande qui regarde dans le répertoire parent (ou le répertoire actuel) supprime tous les dossiers de celui-ci, mais conserve tout le contenu et les fichiers qui ne sont ni un dossier ni contenus dans un dossier.

Je comprends que la suppression d’éléments de la ligne de commande nécessite une attention particulière, mais j’ai déjà pris toutes les précautions nécessaires pour effectuer une sauvegarde à distance.

Evster
la source

Réponses:

62

Sous BASH, vous pouvez utiliser la barre oblique finale (je pense que cela devrait fonctionner dans n’importe quel shell POSIX):

rm -R -- */

Notez le --qui sépare les options des arguments et permet de supprimer les entrées commençant par un trait d'union - sinon, après développement par le shell, le nom de l'entrée serait interprété comme une option par rm(la même chose est valable pour beaucoup d'autres utilitaires de ligne de commande).

Ajoutez cette -foption si vous ne souhaitez pas recevoir de confirmation lors de la suppression de fichiers non inscriptibles.

Notez que par défaut, les répertoires cachés (ceux dont le nom commence par .) seront laissés seuls.

Une mise en garde importante: le développement de */inclura également les liens symboliques qui finissent par se résoudre en fichiers de type répertoire . Et selon l’ rmimplémentation, rm -R -- thelink/supprimera simplement le lien symbolique ou (dans la plupart d’entre eux) le contenu du répertoire lié de manière récursive, mais pas ce répertoire ni le lien symbolique.

Si vous utilisez cette méthode zsh, une meilleure approche consisterait à utiliser un qualificatif glob pour sélectionner uniquement les fichiers de type répertoire:

rm -R -- *(/) # or *(D/) to include hidden ones

ou:

rm -R -- *(-/)

d'inclure des liens symboliques vers des répertoires (mais, cette fois, l'extension ne comporte pas de fin /, c'est uniquement le lien symbolique qui est supprimé avec toutes les rmimplémentations).

Avec bash, AT & T ksh, yashou zshvous pouvez faire:

set -- */
rm -R -- "${@%/}"

dépouiller la fuite /.

Peterph
la source
Magnifique! Cela fonctionne parfaitement. Je n'avais pas réalisé que c'était si facile à faire. Souhaitez-vous élaborer sur le -r vs. -R et ce que font ces commandes? Merci beaucoup.
Evster
-r, -R, --recursiveSont synonymes signifiant « supprimer des répertoires et leur contenu récursive ».
Peter
pouvez-vous expliquer quoi - et * / do?
Amphibient
6
Vous pouvez également dire rm -R ./*/- Cela évite également les problèmes de noms de trait d'union.
l0b0
1
Faites juste attention à ne pas changer l'ordre des * et des /. rm -R - / * fait quelque chose de totalement différent que vous ne voulez peut-être pas arriver: |
ChrisOdney
13

En plus de la méthode générique, vous pouvez également utiliser find(au moins GNU find) pour faire ceci:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 rm -R

Comme avec les autres findlignes, vous pouvez exécuter la première partie ( find -mindepth 1 -maxdepth 1 -type d) pour afficher une liste des répertoires à supprimer.

Une option plus sûre consiste à faire quelque chose comme ceci:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 mv -i -t ../to-rm
# or
mv -i -t ../to-rm */
# or
mv -i */ ../to-rm

N'importe lequel d'entre eux déplacera tous les éléments au ../to-rmlieu de les supprimer. Vous pouvez vérifier qu'il a bien fait ce que vous vouliez, rm -Rfce répertoire à votre guise.

derobert
la source
+1 pour la "Corbeille CLI" to-rmet findqui gère bien les répertoires commençant par un point (en plus de tout autre échappement fastidieux). :)
Peter
Merci pour le conseil. J'aime l'idée de passer à un répertoire séparé avant de supprimer. Je travaille via un terminal sous Mac OS X et je pense que je devrais installer un paquet GNU pour utiliser les commandes -mindepth et -maxdepth, n'est-ce pas?
Evster
@Evster ne sait pas si Mac OS X trouve les prend en charge. Je suppose que fink (est-ce toujours là?) Pourrait installer une découverte qui le fait. Vous pouvez également les omettre, puis filtrer la liste de fichiers générée à l'aide de grep. Utilisez certainement l'option mv sur cela, plutôt que sur rm.
Derobert
4

Vous voudrez peut-être créer un script pour certaines de ces suggestions, en particulier rm -R -- */, et le conserver dans votre dossier / usr / local / bin; ou créez un aliasdans votre fichier ~ / .bashrc. Puisqu'il est si facile de faire une erreur de frappe avec une commande et de casser votre système (même une seule lettre et / ou l'ordre des lettres peuvent avoir des conséquences catastrophiques), cela constituerait une solution un peu plus robuste que de devoir taper les différentes options et arguments chaque fois que vous voulez accomplir cette tâche.

En outre, vous souhaiterez peut-être inclure l' option -i or --interactive=onceou -I or --interactive=alwaysdans votre script / commande, ce qui servira d'autre outil pour éviter les suppressions involontaires.

En outre, quelque chose comme derobert suggéré serait le mieux; copiez / collez simplement le script dans un éditeur de fichier / terminal et ajustez-le à vos besoins spécifiques. Les fichiers / répertoires seront alors déplacés dans un seul répertoire (dont vous pourrez vérifier / vérifier le contenu) que émettre la rm -rfcommande.

Une autre option consiste à utiliser une application graphique, telle que votre gestionnaire de fichiers, et à sélectionner simplement tous les fichiers / dossiers applicables que vous souhaitez supprimer. Vérifiez les pages de manuel de votre distribution si vous n'avez pas les permissions.

Enfin, si les dossiers sont vides (essentiellement des noms de fichiers simples), vous pouvez utiliser la rmdircommande pour les supprimer. Cela ne fonctionne pas pour tout ce que vous voulez supprimer, mais cela vous sera utile lorsque vous voudrez faire du "ménage". ** Vous voudrez peut-être essayer l' -p --ignore-fail-on-non-emptyoption, qui vous permettra de supprimer certains sous-répertoires ainsi que leurs "parents" vides - les répertoires dans lesquels ils résident.

ILMostro_7
la source
C'est une très bonne idée de créer un script distinct pour lequel je peux appeler cette commande. Pouvez-vous expliquer ce que font exactement les options -i et -I? Merci!
Evster
L'option -I vous demandera une fois après avoir appuyé sur "Entrée" de confirmer que vous souhaitez supprimer ceci (lorsqu'il y a plus de 3 fichiers / dossiers "sélectionnés"); tandis que l'option -i émettra une invite pour chaque fichier, sur laquelle vous pourrez simplement confirmer en appuyant sur "y" et "Entrée" - rien en plus d'une réponse affirmative fera que ce fichier spécifique sera ignoré pendant le processus de suppression.
ILMostro_7
1

Tout d’abord, vous devez lister les répertoires puis les supprimer, sans entraver les fichiers normaux. Ls -d * / ne répertorie que les sous-répertoires. Le fait de le diriger avec rm supprime les répertoires et le contenu, tout en préservant les fichiers perdus.

Cette commande devrait faire le travail,

ls -d  */ | xargs rm -rf
Ankit Marothi
la source
1
Quel serait l'avantage sur rm -rf -- */? printf '%s\0' */ | xargs -r0 rm -rf --aiderait (dans les shells où printfest intégré et non ls) à contourner la liste arg de trop grandes erreurs, mais ls -d */ | xargs rm -rfn’ajoute rien AFAICT sauf des problèmes supplémentaires.
Stéphane Chazelas
1
@AnthonyGeoghegan, oui par exemple, s'il y avait un répertoire appelé " .."(espace ..), le contenu du répertoire parent serait supprimé avec certaines lsimplémentations. Et ce ne sont pas seulement des espaces, ce sont aussi d'autres caractères vierges, nouvelle ligne, guillemets simples, guillemets doubles, barres obliques inversées et noms de fichiers commençant par -.
Stéphane Chazelas
2
@Ankit, vous pouvez commencer par mywiki.wooledge.org/ParsingLs
Stéphane Chazelas le
1
Lorsque vous comprenez parfaitement la suggestion de @ StéphaneChazelas d'utiliser printfpour générer une liste dans laquelle chaque nom est terminé par un caractère nul afin qu'il puisse être traité xargsavec l' -0option, je vous conseillerais de modifier votre réponse pour la mettre à jour avec sa variante. Je serais assez confiant dans le fait qu'il serait heureux que vous utilisiez son extrait de code si vous le comprenez bien et avez compris comment il protège contre les comportements indésirables provoqués par certains noms de fichiers potentiellement existants.
Anthony G - justice pour Monica le
1
Utiliser xargsprésente un avantage par rapport à la réponse acceptée (cela fonctionne quand il y a un très grand nombre de fichiers / répertoires dans le répertoire en cours), il est donc possible de l'éditer en une réponse utile. Personnellement, j’ai trouvé que répondre aux questions de Stack Exchange était une bonne expérience d’apprentissage, en particulier lorsque j’obtenais un retour utile d’autres utilisateurs.
Anthony G - justice pour Monica le
-1

rm -rf <directory name>. Ça marche. Le rm <directory name>simple fait de taper conduit simplement au nombre de sous-questions dans lesquelles chacun des sous-répertoires doit être supprimé manuellement. Mais, rm -rfaide à supprimer le répertoire entier avec ses sous-répertoires à la fois.

Riya Melvin
la source
5
L'OP a demandé de conserver le contenu du répertoire actuel.
Stephen Rauch