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


17

Je dois 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

OU

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

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


6
Sous Unix et Linux, nous appelons ces «répertoires», pas «dossiers».
tchrist

1
Selon votre shell, vous devrez peut-être citer cet !opérateur: \!ou '!'.
Toby Speight

Réponses:


32

Cela supprimera tous les dossiers à l'intérieur ./myfoldersauf que ./myfolder/test2et tout son contenu sera conservé:

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

Comment ça fonctionne

  • find démarre une commande find.
  • ./myfolderindique à find de commencer par le répertoire ./myfolderet son contenu.

  • -mindepth 1 pour ne pas correspondre ./myfolder, juste les fichiers et répertoires en dessous.

  • ! -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épertoire 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

1
Alternative à -prunelaisser les test2/*/sous-répertoires seuls: revenir à rm -ret ajouter -maxdepth 1.
Toby Speight

@Isaac OK. Terminé. (Aussi, +1 pour votre excellente réponse.)
John1024

Excellent travail !, mais désolé: cela supprimera tous les fichiers à l' intérieur ./myfolder. Vous avez besoin d'un (IMvhO) manquant -type dpour les répertoires uniquement .
Isaac

Ok, cela devrait fonctionner comme vous le souhaitez:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
Isaac

10

Utilisation de 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

5

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.


L'utilisation -mindepth 1garantit que le répertoire supérieur 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 -not -name test2va pas éviter subdirs à 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 du pruneau:

$ 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 ne l'utilisez pas delete, comme cela implique depthet 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

Soit utiliser rm -rf(supprimer le echosi 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, utilisez égalementmaxdepth si tout ce dont vous avez besoin est de supprimer des répertoires (et tout ce qu'il contient) (supprimez le echopour effacer réellement):

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

Un -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

2

Si vous utilisez zsh, vous pouvez:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

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

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

Vous avez rencontré le même problème que l'OP; lister / home / dossier sur la ligne de commande (sans le critique -mindepth 1) fait que le répertoire supérieur correspond à tous les critères (c'est un répertoire et il n'est pas nommé "test2") et donc il est supprimé.
Jeff Schaller
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.