Rimuovi tutti i file / directory tranne un file


244

Ho una directory che contiene un gran numero di file. Voglio eliminare tutti i file tranne file.txt. Come faccio a fare questo?

Ci sono troppi file per rimuovere singolarmente quelli indesiderati e i loro nomi sono troppo diversi per poterli usare * per rimuoverli tutti tranne questo file.

Qualcuno ha suggerito di usare

rm !(file.txt)

Ma non funziona Restituisce:

Badly placed ()'s 

Il mio sistema operativo è Scientific Linux 6.

Qualche idea?


13
spostare quello che si desidera conservare, quindi gli altri?
Olivier Dulac,

5
@OlivierDulac Siamo le uniche due persone in questa domanda a non pensare troppo alla domanda?
Shadur,

1
@shadur: beh, posso relazionarmi con loro: gli oneliners sono attraenti ... ^^
Olivier Dulac,

1
Grazie e sì, stavo cercando una soluzione a una linea. È troppo tempo per continuare a spostare i file, poiché devo farlo abbastanza spesso.
Kantura,

Risposte:


288

POSIXly:

find . ! -name 'file.txt' -type f -exec rm -f {} +

rimuoverà tutti i file regolari (ricorsivamente, compresi quelli nascosti) tranne file.txt. Per rimuovere le directory, passare -type fa -type de aggiungere l' -ropzione a rm.

In bash, per usare rm -- !(file.txt), è necessario abilitare extglob :

$ shopt -s extglob 
$ rm -- !(file.txt)

(o chiamando bash -O extglob)

Nota che extglobfunziona solo con la bashfamiglia di shell Korn. E l'utilizzo rm -- !(file.txt)può causare un Argument list too longerrore.

In zsh, puoi usare ^per negare il pattern con extendedglob abilitato:

$ setopt extendedglob
$ rm -- ^file.txt

o usando la stessa sintassi con kshe bashcon opzioni ksh_globe no_bare_glob_qualabilitato.


9
Specificare la directory è una buona pratica (percorso completo in questo caso? O forse aggiungere un avviso qui che questo comando cancella tutti i file a partire dalla directory di lavoro corrente ?). Di solito scrivo anche qualsiasi esempio con rmas echo rm, e chiedo alle persone di eliminare l'eco solo quando sono veramente sicuri che farà ciò che vogliono. A parte questo, +1 per la risposta esaustiva
Olivier Dulac,

11
Suggerirei -deleteinvece di -exec, più breve e più facile da ricordare
Izkata,

6
@Izkata: -deletenon definito da POSIX.
cuonglm

5
Come escludere l'elenco di file?
Meysam,

5
@Meysam: vedi la mia risposta per una soluzione che gestirà un elenco di file. Altrimenti con la findsoluzione di Gnouc che puoi fare ! \( -name one_file -o -name two_file \)e così via.
Mikeserv,

112

Un altro prendere in un'altra direzione (se non ci sono spazi nei nomi dei file)

ls | grep -v file.txt | xargs rm

o (funziona anche se ci sono spazi nei nomi dei file)

ls | grep -v file.txt | parallel rm

da man grep:

 -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v is specified by POSIX)

2
Non funzionerà se i nomi dei file hanno uno spazio ...
Matteo

1
Ciao @Matteo, funziona anche con file con spazi, ma devi racchiudere il modello grep tra virgolette, ad es ls | grep -v "a file with spaces.bin" | xargs rm. Questa è grepsintassi normale .
Sebastian

1
@Sebastian Il problema non è il grepma rm. rmotterrà un elenco di argomenti separati da spazio. Prova touch 'a b'; touch 'c d'; ls | grep -v 'a b' | xargs rm: otterrai rm: c: No such file or directoryerm: d: No such file or directory
Matteo,

1
Sì, questo è un problema comune. Vedi le opzioni -print0in finde -0in xargs. Ecco una soluzione alternativa, ma è leggermente scomodo. find . -maxdepth 1 -type f | grep -v 'a b' | tr '\n' '\0' | xargs -0 rm. A proposito, gnu lo parallelgestisce bene (lo uso quasi sempre come sostituto di xargs:ls | grep -v 'a b' | parallel rm
Sebastian

1
Non sono solo spazi, sono tutti spazi vuoti e nuove righe, ma citano anche caratteri (virgolette singole, doppie e barra rovesciata) e nomi di file che iniziano con -.
Stéphane Chazelas,

32

Mantieni una copia, elimina tutto, ripristina copia:

{   rm -rf *
    tar -x
} <<TAR
$(tar -c $one_file)
TAR

In una riga:

{ rm -rf *; tar -x; } <<< $(tar -c $one_file)

Ma ciò richiede una shell che supporti le stringhe qui.


10
Questo è in qualche modo strabiliante.
vschum,

2
@Derek - vedi la modifica.
Mikeserv,

2
Ma se questo viene interrotto a metà strada o se qualcos'altro va storto, il file scompare.
Kasperd,

2
@kasperd - no. Solo se la shell genitore muore tra il tempo di esecuzione rme tar -x. rmpuò fallire quanto vuole.
Mikeserv,

2
Non è più efficiente spostarlo in un'altra directory e spostarlo indietro? Non abbiamo bisogno di occuparci del contenuto del file, ma solo del suo percorso.
leonbloy,

23

stai pensando troppo a questo.

cd ..
mv fulldir/file.txt /tmp/
rm -rf fulldir
mkdir fulldir
mv /tmp/file.txt fulldir/

Fatto.

MODIFICA In realtà, più semplice:

cd ..
ln fulldir/file.txt ./
rm -rf fulldir
mkdir -p fulldir
mv file.txt fulldir/

3
è la stessa cosa che fa la mia risposta. exce [pt non perde alcuna autorizzazione sulla directory.
Mikeserv,

6
Se è un file di grandi dimensioni su un filesystem separato da / tmp e stai provando a rimuovere tutto dalla radice del filesystem verso il basso, spostarlo in un posto sicuro potrebbe non essere un'opzione.
Johnny,

1
Questa è sicuramente la risposta più semplice.
Ben Liyanage,

17

Sul mio SO Scientific Linux 6 funziona:

shopt -s extglob
rm !(file.txt)

Ho anche Debian a 32 bit installato su una macchina virtuale. Quanto sopra non funziona ma quanto segue:

find . -type f ! -name 'file.txt' -delete

1
Vuoi dire che la findsoluzione che ho dato non ha funzionato?
cuonglm

"non ha funzionato" o "non funziona". Sì, anche la tua soluzione find funziona. Grazie.
Kantura,

1
Puoi renderlo più dettagliato? Come "non ha funzionato? Non rimuove altri file o è stato rimosso file.txto altro?
cuonglm

Volevo dire che sul sistema operativo Debian "$ rm! (File.txt)" restituisce "Badly Placeed () 's". Quindi ho provato "$ shopt -s extglob", ma ha restituito: "shopt: comando non trovato". Quindi ho provato la soluzione "trova". Funziona
Kantura,

1
Oh, quindi ovviamente non funziona. shoptnon è tcshincorporato.
cuonglm,

10

Usa rm !("file.txt")invece dirm !(file.txt)


4
Questo non fa assolutamente alcuna differenza. Il problema qui era che l'OP era 1) che non utilizzava una shell che supporta questo formato e 2) anche in bash, è necessario abilitarlo con shopt -s extglob. In ogni caso, la citazione di un nome di file semplice come quello non avrebbe fatto alcuna differenza.
Terdon

1
Per mantenere solo la cartella utils do - rm -rf! ("Utils")
James Jithin,

7

Solo per dare una risposta diversa, è possibile utilizzare il comportamento predefinito di rmnon eliminare le cartelle:

mkdir tmp && mv file.txt tmp  # create tmp dir and move files there
rm                            # delete all other files
mv tmp/* . && rm -rf tmp      # move all files back and delete tmp dir

1

Trovo che questo approccio sia molto semplice, funzioni e non richieda estensioni speciali (che conosco!)

ls --hide=file.txt | xargs rm
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.