Rimuovere tutti i file tranne alcuni da una directory


215

Durante l'utilizzo sudo rm -r, come posso eliminare tutti i file, ad eccezione di quanto segue:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt

5
Sembra una domanda per unix.stackexchange.com
Jason

1
Esistono 2 modi per leggere questa domanda e le risposte esistenti coprono entrambe le interpretazioni: EITHER: (a) preserva i file con i nomi specificati che si trovano direttamente nella directory di destinazione e - come rm -rimplica - elimina tutto il resto, comprese le sottodirectory - anche se contengono file con i nomi specificati; OPPURE: (b) attraversare l'intera sottostruttura della directory di destinazione e, in ciascuna directory, eliminare tutti i file tranne quelli con i nomi elencati.
mklement0

Risposte:


219
find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

Se non si specifica -type ftrova, verranno elencate anche le directory, che potrebbero non essere utili.


O una soluzione più generale usando la combinazione molto utile find | xargs:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

ad esempio, eliminare tutti i file non txt nella directory corrente:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

La combinazione print0e -0è necessaria se ci sono spazi in uno dei nomi di file che devono essere eliminati.


2
sembra che xargs abbia un limite di dimensioni del testo
frazras

26
per eliminare più motivi:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
Siwei Shen 申思维

5
che dire delle directory? eliminerà tutti i file, ma rimuoverà le cartelle ?!
orezvani,

31
Invece di "| xargs rm", find accetta un parametro -delete.
Emil Stenström,

1
invece di -print0 | xargs -0 rm --te puoi-delete
Andy,

151
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

Extglob (Extended Pattern Matching) deve essere abilitato in BASH (se non è abilitato):

shopt -s extglob

2
Ricevo "errore di sintassi vicino al token inaspettato" ('"quando lo faccio shopt -s extglob; rm -rf !(README|LICENSE). Qualche idea sul perché?
Dennis,

@nic non mi ricordo, scusa. Probabilmente ho finito findcon l' utilizzo -deletedell'opzione.
Dennis,

Questa è la soluzione migliore per me e funziona di default sul mio Ubuntu 12.04.4 LTS senza bisogno di
shopt

3
@nic, @Dennis: l'errore di sintassi suggerisce che qualcosa di diverso da quello bashutilizzato, ad esempio dash, dove extglobnon è supportato. Tuttavia, in una shell interattiva bash , il comando NON funzionerà ANCHE come indicato, anche se per motivi diversi. In breve: esegui shopt -s extglobBY STELE; UNA VOLTA ABILITATO SUCCESSO (verificare con shopt extglob), eseguire rm -rf !(README|LICENSE). (Sebbene extglobnon sia ancora abilitato, !(...)viene valutato dall'espansione della cronologia PRIMA che i comandi vengano eseguiti; poiché questo probabilmente non riesce, il comando NEITHER viene eseguito e extglobnon viene mai attivato.)
mklement0

2
@nic, @Dennis, @ mklement0: ho avuto lo stesso problema con "errore di sintassi vicino al token imprevisto (" durante l'esecuzione del comando all'interno di un file .sh (#! / bin / bash) ma non quando lo stavo eseguendo in un comando riga di interfaccia. Si è scoperto che oltre shopt -s extgloball'esecuzione nell'interfaccia della riga di comando, ho dovuto eseguirlo nuovamente nel mio file di script. Questo ha risolto il problema per me.
Ahresse

41

find . | grep -v "excluded files criteria" | xargs rm

Questo elencherà tutti i file nella directory corrente, quindi elencherà tutti quelli che non corrispondono ai tuoi criteri (fai attenzione ai nomi delle directory corrispondenti) e quindi rimuoverli.

Aggiornamento : in base alla tua modifica, se vuoi veramente cancellare tutto dalla directory corrente tranne i file che hai elencato, puoi usarlo:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

Creerà una directory di backup /tmp_backup(hai i privilegi di root, giusto?), Sposta i file che hai elencato in quella directory, elimina ricorsivamente tutto nella directory corrente (sai che sei nella directory giusta, vero?), Sposta torna alla directory corrente tutto da /tmp_backupe, infine, elimina/tmp_backup .

Scelgo la directory di backup da root, perché se stai cercando di eliminare tutto ricorsivamente dalla radice, il tuo sistema avrà grossi problemi.

Sicuramente ci sono modi più eleganti per farlo, ma questo è piuttosto semplice.


2
Funziona anche molto bene con egrep, ad esempio per la pulizia di file in lattice intermedi:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz

comando straordinario! per rimuovere le directory basta cambiare in rm -r
Aris

1
Se si desidera semplicemente eliminare tutto nella directory corrente oltre ai criteri esclusi: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rfunziona molto più velocemente in quanto non è necessario eseguire il drill-down delle directory inutilmente.
Billynoah,

Per quanto riguarda la findpipeline: problemi di efficienza a parte (3 comandi sono usati per quello che findpotrebbe fare da solo), questo non funzionerà come previsto con nomi di file con spazi incorporati e potenzialmente cancellerà i file sbagliati.
mklement0

Un comando che memorizza i file "da salvare" in un'altra posizione ( /tmp_backup) non termina bene se viene interrotto: dal punto di vista dell'utente, tutti i file sono scomparsi, a meno che non sappiano dove andare a cercarli per recuperarli . Per questo motivo non sono favorevole a questo tipo di strategia.
Craig McQueen,

20

Supponendo che i file con tali nomi esistano in più posizioni nella struttura di directory e si desideri preservarli tutti:

find . -type f ! -regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)" -delete

19

È possibile utilizzare la variabile d'ambiente GLOBIGNORE in Bash.

Supponiamo di voler eliminare tutti i file tranne php e sql, quindi è possibile effettuare le seguenti operazioni:

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

Impostare GLOBIGNORE in questo modo ignora php e sql dai caratteri jolly usati come "ls *" o "rm *". Quindi, usando "rm *" dopo aver impostato la variabile si cancellano solo i file txt e tar.gz.


6
+1; Un'alternativa più semplice all'impostazione e al ripristino della GLOBIGNOREvariabile è l'uso di una subshell:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0

19

Preferisco utilizzare l'elenco di query secondarie:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v, --invert-match seleziona linee non corrispondenti

\| Separatore


1
Soluzione elegante
Joshua Salazar

9

Dal momento che nessuno lo ha menzionato:

  • copia i file che non desideri eliminare in un luogo sicuro
  • elimina tutti i file
  • sposta i file copiati nuovamente in posizione

2
È più complicato perché devi prenderti cura delle autorizzazioni dopo averle copiate.
Romolo

2
@RemusAvram È possibile utilizzare gli switch appropriati con cpo rsyncper conservare le autorizzazioni. Comunque, questo è solo un metodo alternativo (dato come suggerimento) che ha il suo posto qui, come risposta al PO.
gniourf_gniourf

Ciò potrebbe non essere appropriato in molte situazioni in cui i file da conservare vengono attivamente utilizzati da altri processi. È anche ingombrante che i file da rimuovere siano solo un piccolo sottoinsieme e che sia coinvolto un gran numero di file.
codeforester

@codeforester: sicuro. Ma ci sono situazioni in cui è appropriato, però ... in realtà non vedo davvero il punto del tuo commento :).
gniourf_gniourf,

6

Puoi scrivere un ciclo for per questo ...%)

for x in *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;

6

Un po 'in ritardo per l'OP, ma si spera utile per chiunque arrivi qui molto più tardi da google ...

Ho trovato la risposta di @awi e commentare -delete di @Jamie Bullock davvero utile. Una semplice utility in modo da poterlo fare in diverse directory ignorando ogni volta nomi e tipi di file diversi con una digitazione minima:

rm_except (o come vuoi nominarlo)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

ad esempio per eliminare tutto tranne i file di testo e foo.bar:

rm_except *.txt foo.bar 

Simile a @mishunika, ma senza la clausola if.


5

Se stai usando zshciò che consiglio vivamente.

rm -rf ^file/folder pattern to avoid

Con extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)

4

Provarlo ha funzionato con:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

ma i nomi con spazi sono (come sempre) difficili. Ho provato anche con Virtualbox\ VMsinvece le virgolette. Elimina sempre quella directory ( Virtualbox VMs).


NON funziona per i file. rm !(myfile.txt)rimuove tutto compresomyfile.txt
khaverim,

dovrebbe essere eseguito per shopt -s extglobprimo come ha sottolineato @ pl1nk
zhuguowei il

Sì, è molto importante attivare il globbing esteso ( extglob ) in bash, lo sto facendo su una base quotidiana, su alcuni Mac nei laboratori: shopt -s extglobe poi cd /Users/alumno/e infine rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) Leggi le informazioni sul
globbing

4

Appena:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

O:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf

Questo non è raccomandato L' lsoutput di analisi può diventare un problema. Vedi qui per informazioni dettagliate.
RJ

2

Rendi immutabili i file. Nemmeno a root sarà permesso di eliminarli.

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

Tutti gli altri file sono stati eliminati.
Alla fine puoi resettarli mutabili.

chattr -i *

0

Questo è simile al commento di @ siwei-shen ma hai bisogno della -obandiera per fare più modelli. La -obandiera sta per "o"

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm


0

Puoi farlo con due sequenze di comandi. Per prima cosa definisci un array con il nome dei file che non vuoi escludere:

files=( backup.tar.gz script.php database.sql info.txt )

Successivamente, scorrere tutti i file nella directory che si desidera escludere, controllando se il nome file è nell'array che non si desidera escludere; in caso contrario, eliminare il file.

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done

Il confronto regex non è corretto: manterrà tutti i file il cui nome è una sottostringa di uno dei file protetti (anche se gli spazi circostanti in qualche modo lo mitigano; ma i nomi dei file possono contenere spazi). È necessario raccogliere un array di tutti i file, quindi sottrarre i file che si desidera escludere da tale array, quindi rimuovere i file rimanenti.
Tripleee,

-1

Poiché nessuno lo ha ancora menzionato, in un caso particolare:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(o solo rm $OLD_FILES)

o

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

Potrebbe essere necessario utilizzare shopt -s nullglobse alcuni file potrebbero essere presenti o meno:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

senza nullglob, echo *.sh *.bash può darti "a.sh b.sh * .bash".

(Detto questo, io stesso preferisco questa risposta , anche se non funziona in OSX)


La risposta esistente di Leonardo Hermoso fa questo con meno bug. Questo fallirà per i nomi di file con spazi; l'utilizzo di un array risolve elegantemente quel particolare problema (e anche in modo meno cruciale evita l'uso di lettere maiuscole per le sue variabili private, che generalmente deve essere evitato).
Tripleee,

-3

Invece di cercare un comando diretto, spostare i file richiesti nella directory temporanea all'esterno della directory corrente. Quindi eliminare tutti i file utilizzando rm *orm -r * .

Quindi spostare i file richiesti nella directory corrente.


Ciò potrebbe non essere appropriato in molte situazioni in cui i file da conservare vengono attivamente utilizzati da altri processi. È anche ingombrante che i file da rimuovere siano solo un piccolo sottoinsieme e che sia coinvolto un gran numero di file.
codeforester

-3

Rimuovi tutto escludi file.name:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf

2
Questo fallirà in modo orribile e potrebbe causare la perdita di dati se la tua directory / file ha spazi o caratteri insoliti. Non dovresti mai analizzare ls. mywiki.wooledge.org/ParsingLs
RJ
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.