Elimina tutte le cartelle all'interno di una cartella tranne una con un nome specifico


17

Devo eliminare tutte le cartelle all'interno di una cartella usando uno script giornaliero. La cartella per quel giorno deve essere lasciata.

La cartella 'myfolder' ha 3 sottocartelle: 'test1', 'test2' e 'test3' Devo eliminare tutto tranne 'test2'.

Sto cercando di abbinare il nome esatto qui:

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

O

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

Questo comando cerca sempre di eliminare anche la cartella principale 'myfolder'! C'è un modo per evitarlo ?


6
In Unix e Linux, chiamiamo queste "directory", non "cartelle".
tchrist

1
A seconda della shell, potrebbe essere necessario citare !quell'operatore: \!o '!'.
Toby Speight,

Risposte:


32

Ciò eliminerà tutte le cartelle all'interno ./myfoldertranne quella ./myfolder/test2e tutto il suo contenuto sarà preservato:

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

Come funziona

  • find avvia un comando di ricerca.
  • ./myfolderdice a find di iniziare con la directory ./myfoldere il suo contenuto.

  • -mindepth 1 non abbinare ./myfolderse stesso, solo i file e le directory sottostanti.

  • ! -regex '^./myfolder/test2\(/.*\)?' dice a find di exclude ( !) qualsiasi file o directory corrispondente all'espressione regolare ^./myfolder/test2\(/.*\)?. ^corrisponde all'inizio del nome del percorso. L'espressione (/.*\)?corrisponde a (a) una barra seguita da qualcosa o (b) nulla.

  • -delete indica a find di eliminare i file corrispondenti (ovvero, non esclusi).

Esempio

Considera una struttura di directory che assomigli;

$ 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

Possiamo eseguire il comando find (senza -delete) per vedere cosa corrisponde:

$ 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

Possiamo verificare che ciò abbia funzionato guardando i file che rimangono:

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

1
Alternativa a -prunelasciare test2/*/solo le sottodirectory: ritorna a rm -re aggiungi -maxdepth 1.
Toby Speight,

@Isaac OK. Fatto. (Inoltre, +1 per la tua risposta eccellente.)
Giovanni 1024

Ottimo lavoro !, ma scusate: questo rimuoverà tutti i file all'interno ./myfolder. È necessario un file mancante (IMvhO) solo-type d per le directory .
Isaac,

Ok, questo dovrebbe funzionare come vuoi:find ./myfolder -depth -mindepth 1 -maxdepth 1 -type d ! -regex '^./myfolder/test2\(/.*\)?'
Isaac

10

Usando bash :

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

Esempio:

$ 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 '{}' \;

Rimuovere l'eco se soddisfatto dell'elenco di file.


L'utilizzo -mindepth 1garantirà che la directory principale non sia selezionata.

$ 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

Ma un -not -name test2si , non evitare subdirs all'interno 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

Per farlo, hai bisogno di qualcosa come la prugna:

$ 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

Ma non usaredelete , come implica depthe che inizierà a cancellare dal percorso più lungo:

$ 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

Utilizzare rm -rf(rimuovere ilecho se si desidera effettivamente cancellare):

$ 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

Oppure, utilizza anchemaxdepth se tutto ciò che serve è eliminare le directory (e tutto ciò che contiene) (rimuovere ilecho per cancellare effettivamente):

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

A -deletecontinuerà a fallire se la directory non è vuota:

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

2

Se stai usando zsh, allora potresti:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2

0

Testato con il comando seguente e ha funzionato bene

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

Hai riscontrato lo stesso problema dell'OP; list / home / cartella sulla riga di comando (senza critiche -mindepth 1) fa sì che la directory superiore corrisponda a tutti i criteri (è una directory e non si chiama "test2") e quindi viene eliminata.
Jeff Schaller
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.