2010-11-08 15 views
19

Eventuali duplicati:
Delete all but the most recent X files in bashcomando bash per eliminare tutti, ma ultimi 5 directory

Ho uno script per creare backup incrementali giornalieri e ho bisogno di eliminare tutti i backup, ma lo scorso 5.

Per esempio, io ho questo cartelle:

 
drwxr-xr-x 4 root root 4096 Oct 29 01:10 2010-10-29 
drwxr-xr-x 4 root root 4096 Oct 30 01:10 2010-10-30 
drwxr-xr-x 4 root root 4096 Oct 31 01:10 2010-10-31 
drwxr-xr-x 4 root root 4096 Nov 1 01:10 2010-11-01 
drwxr-xr-x 4 root root 4096 Nov 2 01:10 2010-11-02 
drwxr-xr-x 4 root root 4096 Nov 3 01:10 2010-11-03 
drwxr-xr-x 4 root root 4096 Nov 4 01:10 2010-11-04 
drwxr-xr-x 4 root root 4096 Nov 5 01:10 2010-11-05 
drwxr-xr-x 4 root root 4096 Nov 6 01:10 2010-11-06 
drwxr-xr-x 4 root root 4096 Nov 7 01:10 2010-11-07 
drwxr-xr-x 4 root root 4096 Nov 8 01:10 2010-11-08 

E devo mantenere solo le ultime 5 directory e cancellare le altre. Dopo il comando eseguire, ho bisogno di avere solo questo:

 
drwxr-xr-x 4 root root 4096 Nov 4 01:10 2010-11-04 
drwxr-xr-x 4 root root 4096 Nov 5 01:10 2010-11-05 
drwxr-xr-x 4 root root 4096 Nov 6 01:10 2010-11-06 
drwxr-xr-x 4 root root 4096 Nov 7 01:10 2010-11-07 
drwxr-xr-x 4 root root 4096 Nov 8 01:10 2010-11-08 

Non ho bisogno di cancellare precedente a 5 giorni, ho bisogno di eliminare tutti tranne 5 ultimi directory :)

Ora sto usando :

find /backup/increment -maxdepth 1 -type d -mtime +5 -exec rm -rf {} \;

Ma ho bisogno di migliorato non basato in tempo :)

EDIT: Questo è un esempio per un server che esegue backup tutti i giorni, ma ho bisogno di uno script che cancelli tutte le cartelle precedenti all'ultima 5 perché il mio computer fa i backup alle 00:10 di notte, ma non tutte le notti il ​​backup è fatto, perché il mio computer non funziona tutti i giorni, e ho bisogno di avere sempre le ultime 5 copie di backup :)

+0

Se non è "basata nel tempo", qual è la sua definizione di "ultima 5"? –

+0

@dogbane grazie ma la soluzione @MartinStettner sembra essere una soluzione più elegante :) – Lito

+0

@David Aggiunto un commento nel post principale. – Lito

risposta

32

utilizzare il comando tail alle linee di stampa a partire dalla linea di n esimo (opzione -n +N):

rm `ls -t | tail -n +6` 

ls -t restituisce la directory corrente in ordine di tempo. tail -n +6 prende le linee che iniziano con la sesta riga. Citando con i backtick si alimenta il risultato della pipe nel comando rm.

vecchia soluzione, non è corretto ...

utilizzare il comando head, che stampa i primi n linee di qualche uscita:

rm `ls -t1 | head -n 5` 

ls -t uscite la directory corrente ordinati per tempo . head -n 5 prende le prime cinque voci dell'output precedente. Citando con i backtick si alimenta il risultato della pipe nel comando rm.

Si prega di provare prima di applicare a dati :) ...

+1

Si dovrebbe usare invece la coda, per le * ultime * n linee. Ma sì, quella soluzione è molto più semplice e migliore della mia. :) –

+1

Che dire: 'rm $ (ls | sort -r | sed 1,5d)'; elencare i nomi in ordine di data; ordinali in ordine inverso (il più recente per primo); cancellare le prime cinque righe; rimuovere ciò che è rimasto. –

+0

@Max: Grazie per aver segnalato il mio errore. Fortunatamente, c'è l'opzione + N per 'tail' (di cui non ero a conoscenza), quindi possiamo ottenere tutte le linee * ma il primo n *. – MartinStettner

0

creare due file fittizi con l'inizio e la data di fine

touch -t 1010290000 before 
touch -t 2011042359 after 

trovare tutti i file tra il 2 file fittizio e "rm -rf" il risultato

find . -newer before \! -newer after -exec rm -rf {} \; 
+0

Qualunque soluzione più elegante? :) – Lito

+0

La soluzione non si baserà su data/ora :) – Lito

1

La prima cosa che è venuta alla mia mente. Non è elegante:

a=0; 
for i in `ls -t`; 
do 
    a=`expr $a + 1`; 
    if [ $a -gt 5 ]; then 
      echo "removing $i"; 
      rm -rf $i 
    fi; 
done 
+0

Non è elegante, ma è una possibile soluzione :) – Lito

0

ls -tr | perl -ne '{@files = <>; print @files [0 .. $ # files-5]} '| xargs -n1 echo rm -rf

Si rimuove l'eco prima di rm -rf per farlo funzionare.

0

Il trucco sarà l'opzione -t di ls, che ordina in base al tempo di modifica, dal più recente al più vecchio.

Una soluzione davvero ingenuo, utilizzando un file temporaneo, potrebbe andare in questo modo:

ls -t > /tmp/file_list 
num_files_to_keep=5 
# wc -l gets the line count of a file 
# first word of wc output is the actual line count, and that's all we need, so 
# delete everything after the space. 
num_files=`wc -l /tmp/file_list | sed "s/ .*//"` 
#if appropriate you should add a check for num_files < num_files_to_keep 
num_files_to_delete=$(($num_files - $num_files_to_keep)) 
rm `tail -n $num_files_to_delete /tmp/file_list` 
Problemi correlati