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