Comment supprimer des répertoires basés sur la sortie `find`?

148

J'émets la commande suivante pour trouver les répertoires .svn:

find . -name ".svn"

Cela me donne les résultats suivants:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

Comment pourrais-je traiter toutes ces lignes rm -frafin de supprimer les répertoires et leur contenu?

Arnaud
la source
3
GNU find a l' -deleteoption.
Marco
5
Ou vous pouvez ajouter -exec rm -r "{}" \;à la fin de la recherche - soyez prudent lorsque vous utilisez rm -r! :)
Drav Sloan
10
@Marco L'option de suppression ne semble pas fonctionner sur les répertoires.
Arnaud
@SuperChafouin Cela fonctionne parfaitement bien ici sur les fichiers et les répertoires. Le fait est qu'il supprime uniquement les répertoires vides et que, lorsque vous le spécifiez, -name ".svn"il correspond uniquement au .svnrépertoire lui-même et non aux fichiers situés dans le .svnrépertoire.
Marco
1
@SuperChafouin, mais ne fonctionnera pas pour les chemins contenant des espaces (utilisez donc -execavec quoted "{}").
Drav Sloan

Réponses:

195

Find peut exécuter des arguments avec l' -execoption pour chaque correspondance trouvée. C'est un mécanisme recommandé car vous pouvez gérer correctement les chemins contenant des espaces / nouvelles lignes et d'autres caractères. Vous devrez supprimer le contenu du répertoire avant de pouvoir le supprimer lui-même; utilisez donc -rla rmcommande pour y parvenir.

Pour votre exemple, vous pouvez émettre:

find . -name ".svn" -exec rm -r "{}" \;

Vous pouvez également demander à find de trouver uniquement les répertoires nommés .svn en ajoutant une -type dcoche:

find . -name ".svn" -type d -exec rm -r "{}" \;

Avertissement Utilisez rm -ravec précaution pour supprimer le dossier et tout son contenu.

Si vous souhaitez supprimer uniquement les répertoires vides ainsi que ceux contenant uniquement des répertoires vides, find peut le faire lui-même avec -deleteet -empty:

find . -name ".svn" -type d -empty -delete
Drav Sloan
la source
22
J'ai vu le conseil de toujours courir -type après -name dans les commandes find, puisque les appels statà obtenir le type coûtent cher. Je viens de l'essayer moi-même sur un assez grand nombre de fichiers, et cela semble être vrai: courir a find . -name 'foo' -type dpris 19 secondes, alors qu'il a find . -type d -name 'foo'fallu 32 secondes. Donc, environ 50% plus de temps pour courir en -typepremier.
spin
6
J'utilise cette commande depuis des années, mais sur Mac, des erreurs me disent que ces répertoires n'existent pas. Même si cela les supprime. Je n'ai jamais vu de messages auparavant.
Chovy
1
Identique à @chovy. Y a-t-il un moyen de se débarrasser de ces messages?
Clément
2
@chovy @ clément C'est parce que findveut voir dans ce dossier pour d'autres correspondances, alors qu'il supprime le dossier en même temps. ~ Je ne sais pas encore comment résoudre ce problème. ~ Correction du problème:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie
5
@chovy @ Clément Je pense que l' -depthargument résout ce problème:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
gimboland
67

Voici un portable encore plus rapide que le moyen de réponse accepté.

Utiliser un +point-virgule au lieu d'un point-virgule comme findterminateur de commande optimise l'utilisation du processeur. Cela peut être important si vous avez beaucoup de .svnsous-répertoires:

find . -name .svn -type d -exec rm -rf {} +

Notez également que vous ne 1 besoin de citer les accolades ici.

1 Sauf si vous utilisez le fishshell.

jlliagre
la source
5
Quelle est la différence entre + et point-virgule? Pourquoi n'utilisons-nous pas d'accolades?
Shicheng Guo
1
@ShichengGuo Avec le point-virgule, il y aura une commande rm par répertoire trouvé, avec le + une commande rm traitera tous les répertoires trouvés (ou au moins un très grand nombre d'entre eux.) Je ne comprends pas votre deuxième question les accolades sont utilisées ici.
Juillet
Je pense que @ShichengGuo signifie pourquoi ne pas citer les accolades ici (@jlliagre a écrit que nous n’avons jamais besoin de les citer). Je ne peux pas trouver de référence pour le moment, mais je comprends que c'est parce que find échappera automatiquement aux chemins remplacés par {}.
Quinn Comendant
La réponse et la question ne sont pas tout à fait correctes sur ce que + fait. Si plusieurs fichiers sont trouvés, alors ';' donnerait une erreur 'ligne de commande trop longue'. + divise les fichiers trouvés dans des lots inférieurs à la longueur de ligne de commande autorisée et exécute la commande pour chaque lot.
gaoithe
1
@goithe J'ai annulé la modification, qui a remplacé une instruction correcte par une autre. L'utilisation + ne réduit pas l'utilisation du processeur. L'utilisation ; n'entraîne pas d'erreur de commande trop longue.
jeudi
27

Supposons que vous utilisez gnu find , vous pouvez utiliser l' -deleteoption:

find . -name test -delete

ce qui est plus facile à retenir.

Chun Yang
la source
Pensez à développer votre publication avec une explication de la commande (ou une documentation pour sauvegarder votre solution). Souvent, une (ou deux) réponses de ligne ne sont pas les plus éclairantes.
HalosGhost
94
Cela ne fonctionne pas sur des répertoires non vides.
Belacqua
2
fonctionne également sur Mac OS X
dessinez
Cela ne fonctionne pas pour les dossiers non vides, mais c'est la solution la plus facile et la plus sûre
RousseauAlexandre le
L'ordre des options est très important, trouver va les exécuter dans l'ordre donc, -delete doit être le dernier
Jose Ignacio Centeno
13

Sur mon ordinateur quand j'utilise:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Les répertoires sont supprimés mais j'obtiens l'erreur:

find: ‘./dirname’: No such file or directory

pour chaque répertoire.

Mes répertoires ne sont pas vides, donc l'option -delete ne fonctionnera pas pour moi. J'ai trouvé la raison de ce comportement ici :

  1. find prend (pas nécessairement) la première entrée du répertoire ./. ce serait par exemple dir.1 /
  2. il le compare au motif 'dir.?'. correspond-il? Oui.
  3. find exécute "rm -r dir.1".
  4. find essaie d'entrer dir.1 / pour trouver le motif dans le répertoire. il ne sait rien de la commande exec.
  5. il ne trouve plus dir.1 /. retourne ENOENT (regardez la sortie strace)

J'ai utilisé cela à la place pour contourner:

rm -r `find . -name dirname -type d`

Gardez à l'esprit que find essaiera toujours de recurse dans des répertoires nommés dirname, ce qui n'est pas vraiment nécessaire et prendra un peu plus de temps. En fonction de la structure de votre répertoire, vous pourrez peut-être contourner ce problème avec l' --depthoption de recherche. De plus, si vous avez une structure de répertoires telle que dirname / foo / dirname, vous obtiendrez des erreurs "Aucun fichier ou répertoire de ce type" de la part de rm. Pour supprimer les erreurs, vous pouvez rediriger stderr vers / dev / null ou utiliser le -fdrapeau (force) avec rm.

Samuel
la source
2
Mauvaise idée: le nom de fichier avec des espaces entraînera toutes sortes de problèmes
Clément
2
Pour les futurs lecteurs: find . -name "to-delete" -print0 | xargs -r0 -- rm -rest une version infaillible qui ne plante pas dans les espaces
Charlie
3
Voir unix.stackexchange.com/a/115869/8257 que vous devez ajouter -prune.
Mapio
1
Ajoutez -prunepour éviter l'erreur "Aucun fichier ou répertoire de ce type".
Julien Carsique
12

Un moyen plus rapide de faire ceci est:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

Si vous avez ".svn" dans un autre ".svn".

Chang Yu-heng
la source
Ce n'est pas très utile si vous voulez trouver les répertoires à supprimer avec les sous-répertoires.
Alexis Wilke
5

Solution spécifique Bash:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion
se ruer
la source
3
Remarque concernant le développement en ligne de commande de globs correspondant à de nombreux fichiers, le nombre de fichiers pouvant être mis en correspondance avec ce mécanisme est limité. bash: /bin/rm: Argument list too long
Si
1
@DravSloan est correct, mais cette limite se situe dans les centaines de milliers de fichiers. C'est quelque chose à garder à l'esprit, mais ne sera probablement pas un problème pour la plupart des gens.
Evilsoup
4

J'ai trouvé que l' -deleteaction fonctionne bien avec le -pathtest. Par exemple, les éléments suivants doivent résoudre le problème des affiches originales:

find . -path '*/.svn*' -delete
Magnus
la source
Êtes-vous sûr? -deleteimplique -depthet supprime bien les répertoires non vides de mon système.
Magnus
Retesté et cela fonctionne. Peut-être que c'était juste une faute de frappe que j'ai corrigée.
Kenorb
J'ai également essayé cette approche et cela a fonctionné - les répertoires ont été supprimés.
Allan