Garder le nombre de files dans le dossier constant en supprimant les anciens files

J'essaie de créer un script et de l'exécuter dans crontab toutes les 5 min, de sorte que le nombre de files dans un dossier rest toujours 50000. S'il y en a plus, je veux que le script supprime les anciens files.

#!/bin/bash LIMIT=500000 NO=0 #Get the number of files, that has `*.pcap` in its name, with last modified time 5 days ago NUMBER=$(find /mnt/md0/capture/DCN/ -maxdepth 1 -name "*.pcap" |wc -l) if [[ $NUMBER -gt $LIMIT ]] #if number greater than limit then del=$(($NUMBER-$LIMIT)) if [ "$del" -lt "$NO" ] then del=$(($del*-1)) fi echo $del FILES=$( find /mnt/md0/capture/DCN/ -maxdepth 1 -type f -name "*.pcap" -print0 | xargs -0 ls -lt | tail -$del | awk '{print $8}' ) rm -f ${FILES[@]} #delete the originals fi 

Cela ne fonctionne pas vraiment, il ne s'exécute pas car le nombre de files est trop grand. Y a-t-il une autre méthode pour faire cela?

J'ai couru la command:

 find /mnt/md0/capture/DCN/ -maxdepth 1 -type f -name "*.pcap" -print0 | xargs -0 ls -lt | tail -n "$del" | awk '{print $8}' 

Le problème que j'ai observé était que awk '{print $8}' imprime l'heure, pas le nom du file. awk '{print $9}' résoudrait cela.

Un autre problème est que xargs peut exécuter ls -lt plusieurs fois ce qui vous donnerait un certain nombre de lists sortingées de files l'un après l'autre, mais toute la list ne serait pas sortingée.

Mais, il semble y avoir d'autres simplifications que l'on pourrait faire. Vous pouvez get les files les plus anciens avec:

 ls -dt /mnt/md0/capture/DCN/*.pcap | tail -n "$del" 

Cela suppose, selon votre post, que les noms de files n'ont pas d'espaces, d'tabs ou de caractères de nouvelle ligne.

Ainsi, la command complète pour supprimer les files $del les plus anciens pourrait être:

 ls -dt /mnt/md0/capture/DCN/*.pcap | tail -n "$del" | xargs rm 

PLUS: si vos noms de files peuvent contenir des espaces, des tabulations, des barres obliques inverses ou des guillemets (mais pas des returns), utilisez (en supposant GNU ls 4.0 (1998) ou plus récent):

 ls -dt --quoting-style=shell-always /mnt/md0/capture/DCN/*.pcap | tail -n "$del" | xargs rm 

Pour ceux qui ne veulent pas faire des hypothèses sur les noms des files:

Avec zsh :

 #! /bin/zsh - keep=5000 rm -f /mnt/md0/capture/DCN/*.pcap(D.om[$((keep+1)),-1]) 

C'est en utilisant les qualificateurs zsh globbing:

  • D : inclut les files cachés (files D ot).
  • . : seuls les files réguliers (comme find 's -type f )
  • om : inverse de l'âge (basé sur le time de m odification)
  • [$((keep+1)),-1] : n'inclure que les 5001 m au dernier.

(cela peut échouer si la list des files à supprimer est très volumineuse, auquel cas vous voudrez peut-être utiliser zargs pour le split ou activer le rm zmodload zsh/files avec zmodload zsh/files ).

Avec des versions relativement récentes d'outils GNU:

 cd /mnt/md0/capture/DCN/ && find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p\0' | sort -zrn | sed -z "s/[^@]*@//;1,$keep d" | xargs -r0 rm -f 

(en supposant GNU sed 4.2.2 ou supérieur (2012) pour -z , GNU sort 1.14 ou supérieur (1996) pour -z )

find construit une list de noms de files délimités par NUL avec un timestamp Unix 1390682991.0859627500@./file (comme 1390682991.0859627500@./file ) qui est sortingé par sort . sed supprime l'horodatage et imprime uniquement à partir du 5001ème logging. C'est passé comme arguments à rm utilisant xargs -r0 .

ou (avec n'importe quelle version des outils GNU):

 cd /mnt/md0/capture/DCN/ && find . -maxdepth 1 -name '*.pcap' -type f -printf '%T@@%p\0' | tr '\0\n' '\n\0' | sort -rn | tail -n "+$(($keep+1))" | cut -d @ -f2- | tr '\0\n' '\n\0' | xargs -r0 rm -f 

Même, sauf que nous utilisons cut pour supprimer l'horodatage et la tail pour sélectionner les lignes à partir de 5001. Comme la cut et la tail GNU ne supportent pas un -z pour travailler sur des loggings délimité par NUL, nous utilisons tr pour permuter la nouvelle ligne et Caractères NUL avant et après l'alimentation des données pour eux.

Avec GNU ls (4.0 (1998) ou supérieur), et bash :

 shopt -s dotglob cd /mnt/md0/capture/DCN/ && eval "files=($(ls -dt --quoting-style=shell-always -- *.pcap))" && rm -f -- "${files[@]:$keep}" 

(cela peut aussi échouer si la list du file est grande) Notez également qu'il peut inclure des files pcap non-réguliers (no -type f )).

En règle générale / POSIXly / portable, c'est beaucoup plus délicat:

 cd /mnt/md0/capture/DCN/ && ls -dt ./.pcap ./.*.pcap ./*.pcap | awk -v keep="$keep" ' function process() { if (++n > keep) { gsub(/[ \t\n"\\'\'']/,"\\\\&", file) print file file = "" } } /\// { if (NR > 1) process() file=$0 next } {file = file "\n" $0} END {if (NR > 0) process()}' | xargs rm -f 

(encore une fois, vous pouvez atteindre la limite du nombre d'arguments, et il ne vérifie pas les files réguliers).

Le bit difficile est de gérer les noms de files avec des caractères newline. Au-dessus, nous passons ./* à ls qui signifie / sera inclus une fois pour chaque nom de file, et nous l'utilisons dans awk pour identifier sur quelle ligne chaque nom de file commence, alors nous soaps quel caractère newline (en plus de tous les autres spéciaux à xargs ) pour échapper à xargs .

En supposant qu'aucun des noms de file ne contienne d'espace, de tabulation, de nouvelle ligne, de guillemet simple, de guillemet double ou de barre oblique inverse, les files les plus anciens sont supprimés

 mkdir t && cd t # 50500 files, 500 to delete touch {000001..050500} limit=50000 ls -t|tail -n "+$(($limit + 1))"|xargs rm ls|wc -l 50000 

tail -n +50001 affiche les files au-dessus de la limite.

Il suffit d'utiliser ls avec le sorting décroissant -t :

 limit=5000 Cnt=0 for line in `ls -t` do if [[ $Cnt -gt $limit ]] then rm $line fi Cnt=`expr $Cnt + 1` done