risposta-alla-domanda-sullo-sviluppo-web-bd.com

Elimina in modo efficiente directory di grandi dimensioni contenenti migliaia di file

Abbiamo un problema con una cartella che diventa ingombrante con centinaia di migliaia di piccoli file.

Ci sono così tanti file che eseguono rm -rf restituisce un errore e invece quello che dobbiamo fare è qualcosa di simile:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

Funziona ma è molto lento e costantemente non riesce a rimanere senza memoria.

C'è un modo migliore per farlo? Idealmente, vorrei rimuovere l'intera directory senza preoccuparsi del contenuto al suo interno.

177
Toby

L'uso di rsync è sorprendentemente veloce e semplice.

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/

La risposta di @ sarath ha menzionato un'altra scelta veloce: Perl! I suoi benchmark sono più veloci di rsync -a --delete.

cd yourdirectory
Perl -e 'for(<*>){((stat)[9]<(unlink))}'

Fonti:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux
238
stevendaniels

Qualcuno su Twitter ha suggerito di utilizzare -delete invece di -exec rm -f{} \;

Ciò ha migliorato l'efficienza del comando, ma utilizza comunque la ricorsione per passare attraverso tutto.

42
Toby

Che dire qualcosa del tipo: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Puoi limitare il numero di file da eliminare contemporaneamente modificando l'argomento per il parametro -n. Sono inclusi anche i nomi dei file con spazi vuoti.

19
digital_infinity

Un trucco intelligente:

rsync -a --delete empty/ your_folder/

È ad alta intensità di CPU, ma è davvero molto veloce. Vedi https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files .html

16
MZAweb

Espandendo uno dei commenti, non penso che tu stia facendo quello che pensi di fare.

Innanzitutto ho creato un'enorme quantità di file, per simulare la tua situazione:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done

Poi ho provato cosa mi aspettavo di fallire e cosa sembra che tu stia facendo nella domanda:

$ rm -r foo/*
bash: /bin/rm: Argument list too long

Ma questo funziona funziona:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory
14
Izkata

Ho avuto l'opportunità di testare -delete paragonato a -exec rm \{\} \; e per me -delete è stata la risposta a questo problema.

Utilizzando -delete ha eliminato i file in una cartella di 400.000 file almeno 1.000 volte più veloce di rm.

L'articolo "Come eliminare un gran numero di file in Linux" suggerisce che è circa tre volte più veloce, ma nel mio test la differenza era molto più drammatica.

10
user2365090

Riguardo a -delete opzione sopra: la sto usando per rimuovere un numero elevato di file (1M + est) in una cartella temporanea che ho creato e che ho inavvertitamente dimenticato di pulire ogni notte. Ho riempito il mio disco/partizione per errore e nient'altro poteva rimuoverli se non il find . comando. È lento, all'inizio stavo usando:

find . -ls -exec rm {} \;

Ma ci voleva un tempo ESTREMO. È iniziato dopo circa 15 minuti per rimuovere alcuni file, ma la mia ipotesi è che rimuovesse meno di una decina di secondi al secondo dopo che finalmente è stato avviato. Quindi, ho provato il:

find . -delete

invece, e lo sto lasciando correre adesso. Sembra funzionare più velocemente, sebbene sia estremamente tassativo sulla CPU che l'altro comando non era. Funziona da circa un'ora e penso che stia recuperando spazio sul mio disco e la partizione "si dimagrisce gradualmente", ma sta ancora impiegando molto tempo. Dubito seriamente che funzioni 1.000 volte più velocemente dell'altro. Come in tutte le cose, volevo solo sottolineare il compromesso tra spazio e tempo. Se hai la larghezza di banda della CPU da risparmiare (lo facciamo), esegui quest'ultima. La mia CPU è in esecuzione (uptime reports):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

E ho visto che la media del carico supera le 30,00, il che non va bene per un sistema occupato, ma per il nostro che è normalmente leggermente caricato, va bene per un paio d'ore. Ho controllato la maggior parte delle altre cose sul sistema e sono ancora reattive, quindi per ora stiamo bene.

5
Scotty

Prendi in considerazione l'utilizzo del volume Btrfs ed elimina semplicemente l'intero volume per tale directory con un numero elevato di file.

In alternativa puoi creare un FS FS quindi smontare ed eliminare il suo file per rimuovere tutto in una volta molto velocemente.

4
Sergei

Uso rm -rf directory invece di rm -rf *.

Inizialmente stavamo facendo rm -rf * mentre si trovava nella directory per cancellare il contenuto e ho pensato che fosse il più veloce possibile. Ma poi uno dei nostri ingegneri senior ha suggerito di evitare l'uso degli asterischi (*) e passa invece nella directory principale, come rm -rf directory.

Dopo un intenso dibattito su come ciò non farebbe differenza, abbiamo deciso di confrontarlo, insieme a un terzo metodo di utilizzo di find. Ecco i risultati:

time rm -rf *                   2m17.32s
time rm -rf directory           0m15.60s
time find directory -delete     0m16.97s

rm -rf directory è circa 9 VOLTE PIÙ RAPIDO di rm -rf *!

Inutile dire che abbiamo comprato quell'ingegnere una birra!

Quindi ora usiamo rm -rf directory; mkdir directory per eliminare la directory e ricrearla.

4
Joshua Pinter

Ci sono un paio di metodi che possono essere usati per cancellare un gran numero di file in Linux. Puoi usare l'opzione find with delete, che è più veloce dell'opzione exec. Quindi puoi usare Perl unlink, quindi anche rsync. Come eliminare un gran numero di file in Linux

4
sarath

Supponendo di avere GNU parallel installato, ho usato questo:

parallel rm -rf dir/{} ::: `ls -f dir/`

ed è stato abbastanza veloce.

2
Nacho

L'eliminazione delle directory DAVVERO GRANDI richiede un approccio diverso, come ho appreso da questo sito - dovrai utilizzare ionice. Assicura (con -c3) che le eliminazioni verranno eseguite solo quando il sistema ha IO- tempo per questo. Il carico dei sistemi non aumenterà fino a raggiungere un livello elevato e tutto rimarrà reattivo (sebbene il tempo di ricerca della mia CPU sia stato piuttosto elevato a circa il 50%).

find <dir> -type f -exec ionice -c3 rm {} \;
1
gamma

Se hai milioni di file e ogni soluzione sopra mette in difficoltà il tuo sistema puoi provare questa ispirazione:

File Nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("[email protected]")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

E ora elimina i file:

find /path/to/folder -type f -exec ./Nice_delete {} \+

Trova creerà batch (vedi getconf ARG_MAX) di alcune decine di migliaia di file e passalo a Nice_delete. Ciò creerà lotti ancora più piccoli per consentire la sospensione quando viene rilevato un sovraccarico.

1
brablc

A seconda di quanto è necessario sbarazzarsi di quei file, suggerirei di usare shred.

$ shred -zuv folder

se si desidera eliminare la directory, ma non è possibile rimuoverla e ricrearla, suggerisco di spostarla e ricrearla all'istante.

mv folder folder_del
mkdir folder
rm -rf folder_del

questo è più veloce, che ci crediate o no, dato che solo un inode deve essere cambiato. Ricorda: non puoi davvero parallelizzare questo gusto su un computer multicore. Dipende dall'accesso al disco, che è limitato dal RAID o da quello che hai.

0
polemon

Gli script Python non devono essere evitati come impuri:

#!/usr/bin/python3

import shutil
path_for_deletion = input( 'path of dir for deletion> ' ) 
print( 'about to remove ' + path_for_deletion + ' ...' )
shutil.rmtree( path_for_deletion, ignore_errors=True )
print( '... done' )

Ho chiesto al ragazzo che ha fatto qualche utile benchmarking di vari metodi qui se poteva provare a benchmarkare questo. Dai miei esperimenti sembra abbastanza buono.

NB gli errori potrebbero essere gestiti almeno per stamparli ... ma potrebbe essere più semplice eseguire trash myDirectoryForDeletion o rm -rfv myDirectoryForDeletion in seguito.

0
mike rodent

Se vuoi semplicemente sbarazzarti di molti file il prima possibile ls -f1 /path/to/folder/with/many/files/ | xargs rm Potrebbe funzionare bene, ma meglio non eseguirlo sui sistemi di produzione perché il tuo sistema potrebbe diventare IO problemi e le applicazioni potrebbero bloccarsi durante l'operazione di eliminazione.

Questo script funziona bene per molti file e non dovrebbe influire sull'ioload del sistema.

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done
0
Leon Kramer

Per il suggerimento di Izkata sopra:

Ma questo funziona :

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

Questo ha funzionato quasi - o avrebbe funzionato - ma ho avuto alcuni problemi con il permesso; i file erano su un server, ma non capisco ancora da dove provenga questo problema di autorizzazione. Ad ogni modo, Terminal ha chiesto conferma su ogni file. La quantità di file era di circa 20.000, quindi questa non era un'opzione. Dopo "-r" ho aggiunto l'opzione "-f", quindi l'intero comando era "rm -r -f foldername / =". Quindi sembrava funzionare bene. Sono alle prime armi con Terminal, ma suppongo che sia andato tutto bene, vero? Grazie!

0
user41527
ls -1 | xargs rm -rf 

dovrebbe funzionare all'interno della cartella principale

0
PsyStyle

Uso ls -f | xargs -n 5000 rm, mentre regola -n per dimensione batch appropriata per il tuo sistema (complimenti a @digital_infinity per -n mancia).

Inoltre puoi filtrare la scheda con un grep inline, ad es. ls -f | grep '^156' | xargs -n 5000 rm.

Nella mia esperienza questo è molto più veloce delle tecniche che usano find e ovvia alla necessità di script Shell più complessi.

0
buckaroo1177125