2010-11-08 8 views
19

Possible en double:
Delete all but the most recent X files in bashcommande Bash pour supprimer tous mais 5 derniers répertoires

J'ai un script pour créer des sauvegardes incrémentielles quotidiennes et je dois supprimer toutes les sauvegardes mais 5 derniers.

Par exemple, j'ai ce dossier:

 
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 

Et je dois maintenir seulement les 5 derniers répertoires et supprimer les autres. Après exécution de commande, je dois avoir seulement ceci:

 
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 

Je ne pas besoin de supprimer avant 5 jours, je dois supprimer tous sauf 5 derniers répertoires :)

Maintenant, je suis en utilisant :

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

Mais je dois amélioré pas basé dans le temps :)

EDIT: Ceci est un exemple pour un serveur qui fait des sauvegardes tous les jours, mais j'ai besoin d'un script qui supprime tous les dossiers précédent 5 parce que mon ordinateur fait des sauvegardes à 00:10 la nuit, mais pas toutes les nuits. mon ordinateur ne fonctionne pas tous les jours, et je dois toujours avoir les 5 dernières sauvegardes :)

+0

Si ce n'est pas « basé dans le temps », quelle est votre définition du « dernier 5 »? –

+0

@dogbane merci, mais la solution @MartinStettner semble être une solution plus élégante :) – Lito

+0

@David Ajouté un commentaire dans la publication principale. – Lito

Répondre

32

utiliser la commande tail aux lignes d'impression en commençant par la n e ligne (Option -n +N):

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

ls -t sort le répertoire courant trié par heure. tail -n +6 prend toutes les lignes commençant par la 6ème ligne. La citation avec des retours arrière alimente le résultat du tube dans la commande rm.

SOLUTION VIEUX, pas correct ...

utilisez la commande head, qui imprime les premiers n lignes de sortie: une

rm `ls -t1 | head -n 5` 

ls -t sorties le répertoire courant triés par le temps . head -n 5 prend les cinq premières entrées de la sortie précédente. La citation avec des retours arrière alimente le résultat du tube dans la commande rm.

S'il vous plaît essayer avant d'appliquer à des données :) ...

+1

Vous voudriez utiliser tail à la place, pour les * dernières * n lignes. Mais oui, cette solution est beaucoup plus simple et meilleure que la mienne. :) –

+1

Qu'en est-il de: 'rm $ (ls | sort -r | sed 1,5d)'; lister les noms dans l'ordre de la date; triez-les en ordre inverse (le plus récent en premier); supprime les cinq premières lignes; Enlevez ce qui reste. –

+0

@Max: Merci d'avoir signalé mon erreur. Heureusement, il y a l'option + N à 'tail' (que je ne connaissais pas), donc nous pouvons obtenir toutes les lignes * mais le premier n *. – MartinStettner

0

créer deux fichiers factices avec le début et la date de fin

touch -t 1010290000 before 
touch -t 2011042359 after 

trouver tous les fichiers entre le 2 fichiers fictifs et "rm -rf" le résultat

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

Une solution plus élégante? :) – Lito

+0

La solution ne sera pas basée sur la date et l'heure :) – Lito

1

La première chose qui est venue à mon avis. Ce n'est pas élégant:

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

Ce n'est pas élégant, mais c'est une solution possible :) – Lito

0

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

Vous supprimez l'écho avant le rm -rf pour le faire fonctionner.

0

L'astuce sera l'option -t de ls, qui trie par heure de modification, du plus récent au plus ancien.

Une solution vraiment naïve, en utilisant un fichier temporaire, pourrait aller dans cette voie:

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` 
Questions connexes