web-dev-qa-db-fra.com

Supprimer tous les dossiers d'un dossier, sauf un avec un nom spécifique

J'ai besoin de supprimer tous les dossiers d'un dossier à l'aide d'un script quotidien. Le dossier de ce jour doit être laissé.

Le dossier 'myfolder' a 3 sous-dossiers: 'test1', 'test2' et 'test3' Je dois tout supprimer sauf 'test2'.

J'essaie de faire correspondre le nom exact ici:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

OR

find /home/myfolder -type d ! -name 'test2' -delete

Cette commande essaie toujours de supprimer le dossier principal "mon dossier" également! Y a-t-il un moyen d'éviter cela?

19
Riju Mahna

Cela supprimera tous les dossiers à l'intérieur de ./myfolder Sauf que ./myfolder/test2 Et tout son contenu seront conservés:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

Comment ça fonctionne

  • find démarre une commande find.
  • ./myfolder Indique à find de commencer par le répertoire ./myfolder Et son contenu.

  • -mindepth 1 Ne correspond pas à ./myfolder Lui-même, juste les fichiers et répertoires sous-jacents.

  • ! -regex '^./myfolder/test2\(/.*\)?' indique à find d'exclure (!) tout fichier ou répertoire correspondant à l'expression régulière ^./myfolder/test2\(/.*\)?. ^ Correspond au début du nom du chemin. L'expression (/.*\)? Correspond soit (a) à une barre oblique suivie de quoi que ce soit ou (b) à rien du tout.

  • -delete Indique à find de supprimer les fichiers correspondants (c'est-à-dire non exclus).

Exemple

Considérez une structure de répertoires qui ressemble à;

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

Nous pouvons exécuter la commande find (sans -delete) Pour voir à quoi cela correspond:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

Nous pouvons vérifier que cela a fonctionné en regardant les fichiers qui restent:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2
33
John1024

en utilisant bash :

shopt -s extglob
rm -r myfolder/!(test2)/

Exemple:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file
10
Jeff Schaller

tl; dr

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

Supprimez l'écho si vous êtes satisfait de la liste des fichiers.


En utilisant -mindepth 1 s'assurera que le répertoire top n'est pas sélectionné.

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Mais un -not -name test2 va pas éviter les sous-répertoires à l'intérieur test2:

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Pour ce faire, vous avez besoin de quelque chose comme Prune:

$ find ./myfolder -mindepth 1 -name test2 -Prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Mais n'utilisez pas delete, car cela implique depth et cela commencera à s'effacer du chemin le plus long:

$ find ./myfolder -depth -mindepth 1 -name test2 -Prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

Utilisez soit rm -rf (supprimez le echo si vous voulez réellement effacer):

$ find ./myfolder -mindepth 1 -name test2 -Prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

Ou, aussi utilisez maxdepth si tout ce dont vous avez besoin est de supprimer les répertoires (et tout ce qu'il y a à l'intérieur) (supprimez echo pour réellement effacer):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

UNE -delete échouera toujours si le répertoire n'est pas vide:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty
5
Isaac

Si vous utilisez zsh, vous pouvez:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2
2
JoL

Testé avec la commande ci-dessous et cela a bien fonctionné

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;
0
Praveen Kumar BS