Come eliminare tutti i file in una directory tranne alcuni?


123

Devo eliminare tutti i file in una directory, ma escluderne alcuni. Ad esempio, in una directory con i file a b c ... z, devo eliminare tutto tranne per ue p. C'è un modo semplice per farlo?


Le risposte di seguito sono molto migliori, ma potresti semplicemente salvare i file in sola lettura, eliminare tutto e poi riportarli alle loro autorizzazioni originali (purché non usi rm -f). Dovresti sapere quali autorizzazioni ripristinare e dovresti sapere che nulla ha avuto bisogno di accedervi durante il processo. Questo è il motivo per cui le altre risposte sono migliori.
Joe,

1
Se si desidera eliminare anche i file nascosti, eseguire shopt -s dotglobprima di eseguirli rm (...).

Risposte:


108

Quello che faccio in questi casi è digitare

rm *

Quindi premo Ctrl+ X, *per espandere * in tutti i nomi di file visibili.

Quindi posso semplicemente rimuovere i due file che mi piace mantenere dall'elenco ed infine eseguire la riga di comando.


25
Immagino che questo funzioni solo finché l'elenco dei file che si *espande troppo non sta diventando troppo lungo. : -}
Frerich Raabe l'

9
Esc seguito da * espande anche "*".
slowpoison

2
@SantoshKumar: Non ha senso per me. L'espansione funzionerà sempre, non dipende dal comando che si desidera utilizzare in seguito.
Der Hochstapler,

2
@OliverSalzburg Siamo spiacenti, la combinazione è un po 'confusa. Penso che dovresti scrivere come Ctrl+ Shift+ x+*
Santosh Kumar il

2
@SantoshKumar: Ma questa non è la combinazione.
Der Hochstapler,

143

A rmtutti ma u,pin bash basta digitare:

rm !(u|p)

Ciò richiede l'impostazione della seguente opzione:

shopt -s extglob

Vedi di più: glob - Greg's Wiki


1
devi avere 'extglobbing' attivo: shopt -s extglob
sparkie

18
Devi shopt -s extglob, @Ashot. Inoltre, sono solo i file, non le directory, ecco perché ho rimosso le -rfopzioni nel tuo comando.
slhck

4
Se è necessario escludere un file di una selezione di file, provate questo: rm !(index).html. Ciò eliminerà tutti i file che terminano con ".html" ad eccezione di "index.html".
mzuther,

71

Puoi usare find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! annulla l'espressione successiva
  • -name specifica un nome file
  • -maxdepth 1farà trovare al processo solo la directory specificata ( findper impostazione predefinita attraversa le directory)
  • -type f elaborerà solo i file (e non ad esempio le directory)
  • -delete cancellerà i file

È quindi possibile ottimizzare le condizioni guardando la pagina man di find

Aggiornare

  • Tieni presente che l'ordine degli elementi delle espressioni è significativo (vedi la documentazione)
  • Metti alla prova il tuo comando prima usando -printinvece di-delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print

5
l'ordine dei predicati è fondamentale qui. Se uno messo -deletesubito dopo .sarà un disastro (eliminerà tutti i file in CWD)
Michał Šrajer

Questo potrebbe essere scritto in modo più compatto comefind . -maxdepth 1 -type f -name '[^up]' -delete
kojiro l'

4
@kojiro sì, ma solo per i file che sono solo una lettera. Con nomi più complessi il regex potrebbe essere un disastro.
Matteo

2
findè il mio migliore amico, specialmente quando ci sono troppi file su glob
Terence Johnson il

43

Semplice:

mvi file desiderati in una directory superiore, rmla directory e poi mvnuovamente.


13
Offcourse, portali in una directory più in alto. Cerca di non trasferirli in una sottodirectory che stai eliminando ...
Konerak,

@Konerak: rmsenza -rrimuovere le sottodirectory.
reinierpost,

11
Questo sovrascriverà i file con lo stesso nome nella directory di destinazione
Matteo

7
Sto sottovalutando questo perché, sebbene possa essere utile, è anche non atomico e rimuove in modo efficace tutti i file dalla directory in un breve periodo di tempo; ciò non sarebbe accettabile se, ad esempio, i file fossero condivisi sulla rete.
Sam Hocevar,

15

Un po 'simile a questa risposta, ma non sono necessarie opzioni speciali, per quanto ne so quanto segue è la funzionalità "antica" supportata da qualsiasi shell (vagamente) / bin / sh simile alla shell (ad esempio bash, zsh, ksh, ecc.)

rm [^up]

2
Funziona con i nomi di file a 1 carattere. Per nomi più lunghi, la risposta di Sparkie è migliore.
Glenn Jackman,

3
Cosa sarebbe sbagliato rm [^up]*? Faccio cose simili piuttosto spesso.
un CVn

3
@ MichaelKjörling - questo eliminerebbe tutti i file che iniziano con u o p, non solo quelli con i nomi up. Penso che l'OP (@Ashot) significasse az e u, p, ecc. simbolicamente e non letteralmente.
Sudipta Chatterjee,

4
@HobbesofCalvin Questo eliminerebbe tutti i file che non iniziano con uop , non quelli che iniziano con loro.
rjmunro,

@rjmunro - grazie, ho perso quello! :)
Sudipta Chatterjee,

11

Farlo senza trovare:

ls | grep -v '(u|p)' | xargs rm

(Modifica: "u" e "v", come in altri luoghi qui, vengono utilizzati come versioni generiche di intere regex. Ovviamente dovrai stare attento ad ancorare le tue regex per evitare di abbinare troppe cose.)

Sicuramente vorrai una sceneggiatura se farai molto di questo, come altri hanno suggerito.


grep non gestirà regexpt esteso per impostazione predefinita: utilizzare -Eoegrep
Matteo

2
questo escluderà qualsiasi file contenente un uo unp
Matteo

@Matteo No, non lo farà. Il grep non sta eseguendo il grepping dei file, bensì il risultato del comando ls. Stai pensando a qualcosa come grep -L (u|p)' * | xargs rmdove -Lsignifica elencare i nomi dei file che non contengono una corrispondenza.
rjmunro,

4
Oh, intendi qualsiasi file il cui nome contiene uo p, non qualsiasi file contenente a uo a p. È corretto. Puoi risolvere usandoegrep -v '^(u|p)$'
rjmunro il

1
Qui è rimuovere tutto tranne queste partite! ls | grep -v 'vuze\|progs' | xargs rm -rf
Nick,

6

In zsh:

setopt extended_glob  # probably in your .zshrc

poi

rm ^(u|p)

o

rm *~(u|p)

La seconda funzionerà anche se avete ^in $histcharsper la sostituzione della storia, e, naturalmente, si può mettere un glob arbitrario prima della ~.


5

GLOBIGNORE prende un elenco separato da due punti

GLOBIGNORE=u:p
rm *

12
Questo non funziona sulla mia shell (GNU bash 4.1.5 (1)). Assicurati di provarlo prima con qualcosa di un po 'meno dannoso dirm o in una directory di test!
un CVn

3

All'epoca del floppy avevo un eseguibile dos chiamato "Tranne" che spostava temporaneamente le cose dalla directory corrente ed eseguiva un comando, quindi potevi dire:

tranne * .txt del *. *

per eliminare tutto tranne i tuoi file di testo.

Questa sarebbe una cosa piuttosto banale da implementare come uno script di shell e se questo è il tipo di cosa che è probabile che tu faccia più di due volte sembra che sarebbe una buona idea.


2
Mi ha ricordato la stessa cosa. Ma passare temporaneamente fuori dalla cartella potrebbe non essere una buona idea nell'era del multitasking :)
Sedat Kapanoglu

3
 find . -maxdepth 1 ! -name "u" ! -name "p" -type f -exec rm -rf {} \;

Ciò eliminerà tutti i file tranne uep in unix


2

Per coloro che preferiscono specificare schemi di esclusione complessi arbitrari (che coprono tutti i nomi di file interessati) in uno stile emge regexp completo, posix-awk o posix-extended style (vedere la pagina man find) raccomanderei questo. Esclude ue pnella directory corrente in questo esempio. Questo può essere utile per gli script.

find -regextype posix-awk ! -regex './(u|p)' -print0 | xargs -0 rm -rf

Devi specificare una directory prima dell'espressione (`find. -Regextype ...).
Matteo

-regextypefunzionerà solo su versioni GNU
Matteo

no - la mia versione find (debian squeeze) non richiede definitivamente una directory esplicita prima dell'espressione se deve essere usata la directory corrente
sparkie

@sparke: funziona solo con implementazioni GNU
Matteo

@sparkie: non definire la directory (primo parametro) per findè un'estensione del findcomando GNU . Lo stesso vale per l' -regextypeopzione. Inoltre, il tuo comando eliminerà i file anche nelle sottodirectory, mentre la domanda originale poneva chiaramente domande sui file in una directory.
Mikko Rantalainen,

1

Uso sempre:

rm [a-o,q-t,v-z]*

Questo ti permetterà di definire quanto granulare vuoi farlo. Quindi, se si desidera eliminare i file da a o Z, è possibile utilizzare:

rm [a-o,z]*

1

Ancora un'altra versione che utilizza xargs:

ls -1 | grep -v do_not_delete | xargs -I files rm "files"

Si noti che xargs -Iè necessario per gestire correttamente i nomi dei file inclusi gli spazi.


1

Ancora un altro:

for FILE in ./*; do if [[ $FILE != ./u* ]] || [[ $FILE != ./p* ]];then rm $FILE; fi; done;

È un po 'lungo e non so se potresti facilmente trasformarlo in una funzione che possa facilmente accogliere e un numero arbitrario di argomenti, ma funziona bene.

Ed è pura bontà bash.


1

Ecco un'altra variante. Puoi digitare:

rm -i *

o:

rm --interactive *

Quindi rmti chiederà di confermare l'eliminazione di ogni file.


1

Uso:

find . -type f ! -name 'u' ! -name 'p' ! -name '*.ext' -delete
find . -type d ! -name 'u' ! -name 'p' ! -name '*.ext' -delete

per eliminare tutti i file comprese le directory, tranne i file u, p e .ext.


0

Un modo semplice che è difficile sbagliare: diciamo che vuoi eliminare tutto tranne * .pdf:

mkdir tmp
mv *.pdf tmp
rm *
mv tmp/* .
rm -r tmp
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.