2009-05-14 27 views
5

Quindi, sembra che ci siano alcune domande che richiedono la rimozione di file/directory corrispondenti a determinati casi, ma sto cercando l'esatto opposto: Elimina TUTTO in una cartella che NON FA abbinare i miei esempi forniti.Elimina tutti i file/directory eccetto due directory specifiche

Per esempio, qui è un albero di directory di esempio:

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

voglio eliminare tutto, ma i file di test/gelato/bigné/e prova/mtndew/livewire /. Tutto il resto può andare, inclusa la struttura della directory. Quindi, come posso ottenere questo? Lingue a cui non dispiacerebbe essere qui: bash o python.

risposta

3

s' -prunefind viene in mente, ma è un dolore per farlo funzionare per i percorsi specifici (icecream/cupcake/) piuttosto che directory specifiche (cupcake/).

Personalmente, mi basta usare cpio e duro-link (per evitare di dover copiare loro) i file nelle directory che si desidera conservare per un nuovo albero e quindi rimuovere il vecchio:

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

Ciò manterrà anche la struttura della directory esistente per le directory che si intende conservare.

0

utilizzare find.

Il comando sarà simile:

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

provato questo, e dice il seguente: find/home/Phuzion/test/\\ (-prune 'gelato/bigné /' \\) -delete ritrovamento: i percorsi devono precedere l'espressione – phuzion

+0

Dalla pagina man per trovare: "Poiché -eliminare implica -depth, non è possibile utilizzare utilmente -prune e -delete insieme." –

+0

La sintassi corretta sarebbe più simile a "trova $ directory -path ./pepsi/diet -prune -o -exec some-command '{}' \;" comunque per eliminare quel messaggio di errore. –

2

Si potrebbe fare qualcosa in base a Python's os.walk function:.

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

... basta aggiungere qualcosa di ignorare i percorsi che ti interessa

3

Tutto "tranne" è il motivo per cui abbiamo le dichiarazioni if; e perché la lista delle directory di os.walk è una lista mutabile.

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

Sposta il materiale che desideri conservare altrove, quindi elimina ciò che rimane.

0

Un oneliner per risolvere il problema:

ritrovamento. | grep -v "test/icecream/cupcake /" | grep -v "test/mtndew/livewire /" | xargs rm -r

Rimosso dal momento che non funziona

questo potrebbe ottenere nei guai se hanno nomi di file con lo spazio in loro, e potrebbe continuare più file che vuoi se ci sono altri alberi che corrispondono ai modelli.

Una soluzione un po 'meglio:

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

In realtà non testato, se si rompe si arriva a mantenere entrambe le parti.

Edit: Come rileva Dennis suoi non soltanto due parti che si rompe in :-) corretti gli errori di battitura nel secondo esempio e rimosso il primo

+0

Nel tuo primo esempio, rm -r test/icecream includerà cupcake (ad esempio). Quindi, anche se hai grep -v i cupcakes, loro vengono ancora "mangiati". Il secondo esempio ha un paio di errori di battitura e virgolette singole sbilanciate.Ci dovrebbe essere uno spazio dopo sed e lo zero dovrebbe essere una e commerciale. –

+0

Sono ancora presenti virgolette singole sbilanciate attorno ai tracciati. Ad esempio, dovrebbe essere "rm" ./test/icecream/cupcake/ "" –

5

Questo comando lascerà solo i file desiderati nelle directory originali:

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

Nessuna necessità di cpio. Funziona su Ubuntu, Debian 5 e Mac OS X.

Su Linux, segnalerà che non è possibile eliminare le directory non vuote, che è esattamente il risultato desiderato. Su Mac OS X, farà tranquillamente la cosa giusta.

+0

Questo trova il test e lo elimina, eliminando così le directory che stai cercando di salvare. –

+0

Questo trova il test e NON lo elimina, perché non è vuoto. Ci sono sapori moderni di Linux o Unix in cui questo comando non funziona? –

+0

Spiacente, ho commesso un errore durante la configurazione del test sul mio sistema. Il tuo esempio funziona correttamente per me. –

0

Funziona per me con find utilizzando due passaggi: prima cancella i file consentiti, quindi le loro directory vuote!

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 
+0

Su ubuntu, find non ha -x -E, quindi l'equivalente sarebbe: find ~/Desktop/test -xdev -regextype posix-extended-not \ (-type d -regex '. */(Cupcake | livewire) /*.* '-prune \) -print0 | xargs -0 ls -1 -dG –

+0

Inoltre, potrebbe essere necessario in alcuni casi per proteggere le directory vuote che si desidera continuare a utilizzare la stessa espressione regolare nel comando find -empty che si trova nell'ultimo passaggio della risposta. Potresti voler chiarire che il tuo primo comando è un test per la dimostrazione del concetto e altrimenti non fa parte dei due passaggi che stai dimostrando. –

0

Come altri ho usato os.walk e os.path.join per costruire la lista dei file da eliminare, con fnmatch.fnmatch per selezionare i file che devono essere inclusi o esclusi:

#-------------------------------# 
# 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 (AttributeError, TypeError) : 
    pass 

Se fnmatch non è sufficiente, è possibile utilizzare il modulo re per verificare i modelli.

Qui ho creato l'elenco dei file prima di fare qualsiasi cosa con esso, ma è possibile elaborare i file così come vengono generati.

Il blocco try/except ... è nel caso in cui l'istanza della classe options non abbia un pattern di esclusione, o se causi un'eccezione in fnmatch perché è il tipo sbagliato.

Una limitazione di questo metodo è che prima comprende file corrispondenti ad un modello, quindi esclude. Se hai bisogno di più flessibilità di questo (includi il modello di corrispondenza a, ma non il modello b a meno che il modello c ...), allora il frammento sopra non è all'altezza. In effetti, lavorando attraverso questo esercizio, inizi a capire perché la sintassi del comando find è così com'è. Sembra goffo, ma in realtà è esattamente il modo di farlo.

Ma se si genera un elenco, è possibile filtrarlo in base alle regole di inclusione/esclusione necessarie.

Una cosa bella di generare un elenco è che è possibile controllarlo prima di procedere con la cancellazione. Questa è una specie di opzione "--dryrun". Puoi farlo in modo interattivo nell'interprete python, stampare l'elenco per vedere come appare, applicare il filtro successivo, vedere se è stato rimosso troppo o troppo poco e così via.

2
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 

È un po 'noioso scrivere tutti i percorsi da conservare ma questo è l'unico modo per utilizzare trova da solo.

Problemi correlati