Eliminazione di milioni di file


38

Ho avuto un dir pieno di milioni di immagini gif. Troppi per il comando rm.

Ho provato il comando find in questo modo:

find . -name "*.gif" -print0 | xargs -0 rm

Il problema è che impantana la mia macchina davvero male e provoca timeout per i clienti poiché è un server.

Esiste un modo più veloce per eliminare tutti questi file ... senza bloccare la macchina?


Sono a una velocità di cancellazione di circa 6 gb / ora usando il comando "nice find" di seguito. Probabilmente ci vorranno 48 ore per eliminare tutti i file. "orizzonte degli eventi" con comando rm, poi è fuggito.

3
Rimuovere l'intera directory non sarebbe sostanzialmente più veloce? Basta estrarre i file "buoni" prima di
cancellare

Bene, in questo momento ogni file è danneggiato, perché è stato spostato in / dir_old e ho rifatto la / dir. Ma rmdir non avrà lo stesso limite di rm *?

@Corepuncher: mi aspetto che rimuovere l'intera directory (come con rm -rfsarebbe più veloce. Vale la pena provare.
Jason R

Attualmente sto eseguendo "rm -rf" sulla directory. Funziona da oltre 20 minuti ... nessun cambiamento nelle dimensioni del disco. Ma non ha nemmeno restituito automaticamente "lista argomenti troppo lunga". L'unico problema è che sta davvero martellando la mia macchina e facendo rallentare / fallire altre cose. Non sono sicuro di quanto tempo lasciarlo andare.

Risposte:


44

Più veloce non è necessariamente quello che vuoi. Potresti voler eseguire effettivamente più lentamente , quindi l'eliminazione consuma meno risorse mentre è in esecuzione.

Usa nice (1) per ridurre la priorità di un comando.

nice find . -name "*.gif" -delete

Per i processi associati a I / O nice (1) potrebbe non essere sufficiente. Lo scheduler di Linux prende in considerazione l'I / O, non solo la CPU, ma potrebbe essere necessario un controllo più preciso della priorità di I / O.

ionice -c 2 -n 7 find . -name "*.gif" -delete

Se ciò non lo fa, puoi anche aggiungere un sonno per rallentarlo davvero.

find . -name "*.gif" -exec sleep 0.01 \; -delete

3
wow ... milioni di file con un sonno di 0,1 s ... ha bisogno di un giorno per 864000 file.
glglgl,

7
@glglgl Va bene, culo intelligente. Ho cambiato il timeout. :-P
John Kugelman supporta Monica il

28
Il sonno può essere una buona scelta, ma bello non lo farà, poiché l'attività qui è associata a IO, non alla CPU; puoi provare invece ionice. Notare che se il sonno è troppo piccolo sarà inutile.
Matteo Italia,

3
@glglgl: il punto è esattamente che se non vuoi causare l'interruzione del servizio sul server devi andare lentamente, il tempo in cui questo codice dorme è lì per consentire al server di lavorare davvero utile con il disco.
Matteo Italia,

1
+1 per l' sleepaggiunta - Ho riscontrato problemi con i server che soffocano sull'IO nonostante l'utilizzo ionice -c 3. Si aggiunge in modo significativo al tempo necessario per cancellare i file (ovviamente), ma preferirei piuttosto che abbattere l'applicazione ...
Ola Tuvesson,

22

Dal momento che stai eseguendo Linux e questa attività è probabilmente legata all'I / O, ti consiglio di dare priorità al tuo scheduler I / O inattivo utilizzando ionice(1):

ionice -c3 find . -name '*.gif' -delete

Rispetto al comando originale, immagino che questo potrebbe anche risparmiare qualche altro ciclo della CPU evitando la pipa xargs.


@Braiam Che vuoi dire? Questo non è find ... -execdove avrebbe senso.

Oh, sì, scusa. Colpa mia. Sei sicuro che sia efficiente, però?
Braiam,

1
Bene, la find(1)documentazione lo afferma. :) E dovrebbe essere ovvio che lasciarsi findrimuovere i file è più efficiente che eseguire un rmcomando per questo.

1
Ho provato diverse versioni suggerite su una cartella con 4 milioni di file su un server di produzione e questa è l'unica che non blocca il sistema. ionice -c3abbassa il prio per eseguire solo quando l'IO è inattivo altrimenti questo è perfetto. Si noti che poiché -deletenon è standard per la ricerca, è possibile fare lo stesso (incluso il feedback che funziona) utilizzando questo comando: ionice -c 3 find . -name '*.gif' -exec echo {} \; -exec rm {} \;- Lento ma nessun passaggio di processi importanti.
Christopher Lörken,

13

No.

Non esiste un modo più rapido, a parte il formato soft del disco. I file vengono dati immediatamente a rm (fino al limite della riga di comando, potrebbe anche essere impostato su xargs), il che è molto meglio che chiamare rm su ciascun file. Quindi no, sicuramente non c'è modo più veloce.

L'uso nice(o renicedurante un processo in esecuzione) aiuta solo parzialmente, perché serve per programmare la risorsa CPU , non il disco! E l'utilizzo della CPU sarà molto basso. Questa è una debolezza di Linux - se un processo "consuma" il disco (cioè funziona molto con esso), l'intera macchina si blocca. Il kernel modificato per l'utilizzo in tempo reale potrebbe essere una soluzione.

Quello che farei sul server è lasciare che altri processi facciano il loro lavoro manualmente, includendo pause per "respirare" il server:

find . -name "*.gif" > files
split -l 100 files files.
for F in files.* do
    cat $F | xargs rm
    sleep 5 
done

Questo attenderà 5 secondi dopo ogni 100 file. Ci vorrà molto più tempo ma i tuoi clienti non dovrebbero notare alcun ritardo.


"I file vengono dati a rm in una sola volta (fino al limite della riga di comando", quindi quando la shell viene ordinata rm *, si espande *nella riga con tutti i nomi di file e la passa a rm? È incredibilmente stupido. Perché shell espandere i caratteri jolly?

MrGreen @Joker_vD, stai scherzando, come suggerisce il tuo nome? :-)
Tomas,

2
@Joker_vD: compatibilità con una decisione Unix del 1970 o giù di lì. Windows non lo fa. Qui, i programmi possono passare caratteri jolly a FindNextFile / FindNextFile, in modo da ottenere i risultati uno alla volta.
MSalters il

@Tomas Non in questo caso. Onestamente, posso vedere immediatamente 2 problemi con tale design: in primo luogo, la riga di comando non è in gomma; in secondo luogo, il programma non può dire se è stato chiamato con *o /*dare un dubbio a tale decisione dell'utente.

1
@Joker_vD Ci sono molte cose buone riguardo alla shell che fa l'espansione jolly. È diverso da Windows, ma non saltare alla conclusione che è incredibilmente stupido semplicemente perché è diverso da quello a cui sei abituato. Se vuoi saperne di più, ti incoraggio a Google o pubblicare una domanda sul sito Stack Exchange pertinente. È un grande deragliamento per quest'area commenti.
John Kugelman sostiene Monica il

5

Se il numero di file che devono essere eliminati supera di gran lunga il numero di file lasciati indietro, potrebbe non essere l'approccio più efficiente camminare sull'albero dei file da eliminare e fare tutti quegli aggiornamenti del filesystem. (È analogo a fare una goffa gestione della memoria contata con riferimento ai riferimenti, visitare ogni oggetto in un grande albero per rilasciare il suo riferimento, invece di trasformare tutto ciò che non desiderato nella spazzatura in un solo passaggio, e quindi spazzare attraverso ciò che è raggiungibile per ripulire.)

Vale a dire, clonare le parti dell'albero che devono essere mantenute su un altro volume. Ricreare un nuovo filesystem vuoto sul volume originale. Copia i file conservati nei loro percorsi originali. Questo è vagamente simile alla copia della raccolta dei rifiuti .

Ci saranno dei tempi di inattività, ma potrebbe essere migliore delle continue cattive prestazioni e interruzione del servizio.

Potrebbe non essere pratico nel tuo sistema e nella tua situazione, ma è facile immaginare casi ovvi in ​​cui questa è la strada da percorrere.

Ad esempio, supponiamo di voler eliminare tutti i file in un filesystem. Quale sarebbe il punto di ricorrere e cancellare uno per uno? Basta smontarlo e fare un "mkfs" sopra la partizione per creare un filesystem vuoto.

O supponi di voler eliminare tutti i file tranne una mezza dozzina di file importanti? Prendi la mezza dozzina da lì e ... "mkfs" sopra.

Alla fine c'è un punto di pareggio quando ci sono abbastanza file che devono rimanere, che diventa più economico fare la cancellazione ricorsiva, tenendo conto di altri costi come qualsiasi tempo morto.


4

Hai provato:

find . -name "*.gif" -exec rm {} +

Il segno + alla fine farà sì che find includa più file per l'esecuzione del singolo comando rm. Controlla questa domanda per maggiori dettagli.


Esegue molto più velocemente di -print0 | soluzione xargs perché il processo rm non è invocato per ogni file ma per un grande set di essi e quindi causa un carico inferiore.

@JohnKugelman Hai ragione, ma è un'estensione GNU che non è sempre disponibile con il comando find nativo .
CodeGnome

OK, interessante, ma questa è una cosa abbastanza nuova (così come -delete) che non deve sempre essere lì ..
Tomas

Tuttavia, ciò non porta certamente nulla di meglio rispetto alla soluzione del PO.
Tomas,
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.