Supprimer tous les fichiers / répertoires sauf deux répertoires spécifiques

Donc, il semble y avoir quelques questions sur la suppression de fichiers / répertoires correspondant à certains cas, mais je cherche l’exact opposé: Supprimez TOUT dans un dossier qui ne correspond PAS à mes exemples fournis.

Par exemple, voici un exemple d’arborescence de répertoires:

. |-- coke | |-- diet | |-- regular | `-- vanilla |-- icecream | |-- chocolate | |-- cookiedough | |-- cupcake | | |-- file1.txt | | |-- file2.txt | | |-- file3.txt | | |-- file4.txt | | `-- file5.txt | `-- vanilla |-- lol.txt |-- mtndew | |-- classic | |-- codered | |-- livewire | | |-- file1.txt | | |-- file2.txt | | |-- file3.txt | | |-- file4.txt | | `-- file5.txt | `-- throwback `-- pepsi |-- blue |-- classic |-- diet `-- throwback 

Je veux tout supprimer sauf les fichiers dans test / icecream / cupcake / et test / mtndew / livewire /. Tout le rest peut aller, y compris la structure du répertoire. Alors, comment puis-je y arriver? Langues Je ne serais pas dérangé par ceci: bash ou python.

find -prune find ‘s -prune , mais c’est pénible de le faire fonctionner pour des chemins spécifiques ( icecream/cupcake/ ) plutôt que des répertoires spécifiques ( cupcake/ ).

Personnellement, je voudrais juste utiliser cpio et hard-link (pour ne pas avoir à les copier) les fichiers des répertoires que vous souhaitez conserver sur un nouvel arbre, puis supprimer l’ancien:

 find test -path 'test/icecream/cupcake/*' -o -path 'test/mtndew/livewire/*' | cpio -padluv test-keep rm -rf test 

Cela gardera également votre structure de répertoires existante pour les répertoires que vous avez l’intention de conserver.

Cette commande ne laissera que les fichiers souhaités dans leurs répertoires d’origine:

 find test \( ! -path "test/mtndew/livewire/*" ! -path "test/icecream/cupcake/*" \) -delete 

Pas besoin de cpio. Il fonctionne sur Ubuntu, Debian 5 et Mac OS X.

Sous Linux, il indiquera qu’il ne peut pas supprimer les répertoires non vides, ce qui est exactement le résultat souhaité. Sur Mac OS X, il fera discrètement le bon choix.

Tout “sauf” est la raison pour laquelle nous avons des déclarations if; et pourquoi la liste des répertoires os.walk est une liste modifiable.

 for path, dirs, files in os.walk( 'root' ): if 'coke' in dirs: dirs.remove('coke') dirs.remove('pepsi') 

Vous pourriez faire quelque chose basé sur la fonction os.walk de Python :

 import os for root, dirs, files in os.walk(top, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name)) 

… ajoutez simplement quelque chose pour ignorer les chemins qui vous intéressent.

Déplacez les éléments que vous souhaitez conserver ailleurs, puis supprimez ce qui rest.

 find /path/to/test/ -depth -mindepth 1 \ ! -path "/path/to/test/icecream/cupcake/*" \ ! -path "/path/to/test/icecream/cupcake" \ ! -path "/path/to/test/icecream" \ ! -path "/path/to/test/mtndew/livewire/*" \ ! -path "/path/to/test/mtndew/livewire" \ ! -path "/path/to/test/mtndew" -delete -print 

Il est un peu fastidieux d’écrire tous les chemins à préserver, mais c’est le seul moyen de trouver seul.

utiliser find

Votre commande ressemblera à quelque chose comme:

 find $directory \( -prune 'some pattern' \) -delete 

Cela fonctionne pour moi avec trouver en utilisant deux étapes: d’abord supprimer les fichiers autorisés, puis leurs répertoires vides!

 find -x -E ~/Desktop/test -not \( -type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -print0 | xargs -0 ls -1 -dG # delete the files first # Mac OS X 10.4 find -x -E ~/Desktop/test -not \( -type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -type f -exec /bin/rm -fv '{}' \; # Mac OS X 10.5 find -x -E ~/Desktop/test -not \( -type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -type f -exec /bin/rm -fv '{}' + # delete empty directories find -x ~/Desktop/test -type d -empty -delete 

Comme d’autres, j’ai utilisé os.walk et os.path.join pour créer la liste des fichiers à supprimer, avec fnmatch.fnmatch pour sélectionner les fichiers à inclure ou à exclure:

 #-------------------------------# # make list of files to display # #-------------------------------# displayList = [] for imageDir in args : for root,dirs,files in os.walk(imageDir) : for filename in files : pathname = os.path.join( root, filename ) if fnmatch.fnmatch( pathname, options.includePattern ) : displayList.append( pathname ) #----# now filter out excluded patterns #----# try : if len(options.excludePattern) > 0 : for pattern in options.excludePattern : displayList = [pathname for pathname in displayList if not fnmatch.fnmatch( pathname, pattern ) ] except ( AtsortingbuteError, TypeError ) : pass 

Si fnmatch ne suffit pas, vous pouvez utiliser le module re pour tester les patterns.

Ici, j’ai construit la liste de fichiers avant de faire quoi que ce soit, mais vous pouvez traiter les fichiers au fur et à mesure qu’ils sont générés.

Le bloc try / except … existe si mon instance de classe d’options n’a pas de modèle d’exclusion ou si elle génère une exception dans fnmatch car il s’agit d’un type incorrect.

Une limitation de cette méthode est qu’elle inclut d’ abord les fichiers correspondant à un modèle, puis les exclut . Si vous avez besoin de plus de flexibilité (incluez le modèle de correspondance a, mais pas le modèle b sauf si le modèle c …), alors le fragment ci-dessus n’est pas à la hauteur. En fait, tout au long de cet exercice, vous commencez à comprendre pourquoi la syntaxe de la commande find est la même. Semble maladroit, mais en fait c’est exactement la façon de le faire.

Mais si vous générez une liste, vous pouvez la filtrer en fonction des règles d’inclusion / exclusion dont vous avez besoin.

Une bonne chose à propos de la création d’une liste est que vous pouvez la vérifier avant de procéder à la suppression. C’est une sorte d’option ‘–dryrun’. Vous pouvez le faire de manière interactive dans l’interpréteur python, imprimer la liste pour voir à quoi elle ressemble, appliquer le filtre suivant, voir si elle a été supprimée trop ou trop peu, etc.

Un oniner pour résoudre le problème:

trouver . | grep -v “test / icecream / cupcake /” | grep -v “test / mtndew / livewire /” | xargs rm -r

Supprimé puisqu’il ne fonctionne pas

Cela peut vous causer des problèmes si vous avez des noms de fichiers contenant de l’espace, et que cela risque de contenir plus de fichiers si vous voulez que d’autres arbres correspondent aux modèles.

Une solution un peu meilleure:

 find . |sed "s/.*/rm '&'/"|grep -v "rm './test/icecream/cupcake/"| grep -v "rm './test/mtndew/livewire/"|sh 

Non testé, s’il se casse, vous obtenez les deux parties.

Edit: Comme Dennis pointe non seulement ses deux parties qu’il brise 🙂 corrigé les fautes de frappe dans le deuxième exemple et enlevé le premier