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?

Riju Mahna
la source
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
John1024
la source
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
Jeff Schaller
la source
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
Isaac
la source
2

Si vous utilisez zsh, vous pouvez:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2
JoL
la source
0

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

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;
Praveen Kumar BS
la source
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