J'ai un fichier texte qui contient des enregistrements de la forme:
text text <2018.02.20-13.05.22> [dataset-london] text text text
text text <2018.02.20-13.05.25> [dataset-newyork] text text text
text text <2018.02.20-13.05.22> [dataset-moscow] text text text
text text <2018.02.20-13.07.45> [dataset-london] text text text
text text <2018.02.20-13.09.55> [dataset-paris] text text text
Il y a environ 20 jeux de données, et les enregistrements pour chacun sont ajoutés à un rythme d'un enregistrement toutes les 15 minutes lorsque tout va bien, mais il peut y avoir des périodes pendant lesquelles les enregistrements ne sont pas reçus, ou les enregistrements sont ajoutés plus rapidement.
Les enregistrements ont un jeu de caractères limité de [0-9a-zA-Z -._ @] plus les caractères spéciaux & lt; & gt; [] comme délimiteurs, comme dans les exemples de lignes.
Pour limiter le nombre d'enregistrements, les enregistrements sont étiquetés après un certain temps comme "secondaires" - peu importants - peuvent être ignorés - en ajoutant un "*" à la fin de la ligne. L'algorithme que j'utilise consiste à transmettre le fichier sed
et utilisez regex find / replace pour baliser temporairement les lignes en fonction de la question de savoir si vous pouvez les conserver, puis dirigez-les vers sed
à nouveau pour supprimer les balises temporaires et toutes les lignes sans balise temporaire sont maintenant marquées comme secondaires. Cela donne un aperçu de la façon dont je le fais (j'ai laissé de côté les continuations '\' pour plus de clarté):
cat input_file |
sed -E '/(`date '+%Y\.%m\.%d'`|`date -v-1d '+%Y\.%m\.%d'`)/ s/$/#/' |
sed -E '/00\.00\.[0-9]{2}>/ s/$/#/' |
sed '/#$/! s/$/*/' |
sed -E 's/#+$//'
> output_file
Explication du code CLI:
- Recherchez chaque ligne avec une date au cours des 2 derniers jours et ajoutez un marqueur temporaire ("+"), ...
- Trouve chaque ligne avec l'heure dans la minute 1 (généralement le premier enregistrement du jour pour chaque jeu de données) et ajoute un marqueur temporaire, ...
- N'importe quoi ne pas marqué temporairement est considéré comme un enregistrement secondaire et se voit attribuer un *, ...
- Enfin, tous les marquages temporaires sont supprimés.
C'est brut mais fonctionne bien et est flexible.
Mon problème est que je veux garder "le premier enregistrement de chaque jour pour chaque jeu de données". En ce moment, j'utilise "dans la minute qui suit minuit" pour me rapprocher de cela, et je m'appuie sur des enregistrements uniques de jeu de données au cours de cette minute. Cela fonctionne à 100% si tout se passe bien, mais s'il y avait une période exceptionnelle pendant laquelle le chronométrage habituel des disques était perturbé, cela ne fonctionnerait pas. Par exemple, si les enregistrements ont tous été retardés d'une minute au cours d'une certaine période, il semblerait que nous ne disposions d'aucun "enregistrement important" au cours de cette période, car il est impossible de savoir que l'enregistrement daté du 2018.02.20-00.01.01 est en réalité le premier enregistrement de la journée pour cet ensemble de données, parce que je vérifie "bêtement" des enregistrements contenant 20NN.NN.NN-00.00.NN>
seulement.
Je connais sed
, moins familier avec awk
que je soupçonne peut être l'outil dont j'ai besoin.
Comment puis-je rendre cela plus intelligent, pour que le premier enregistrement de chaque jour, ou le premier après le 15 du mois, ou autre, puisse être déterminé, afin que les enregistrements importants ne soient pas invisibles, marqué comme secondaire.
la source
Explanation of CLI code
faire les conditions.awk 'BEGIN { two_days_ago=systime()-172800}; { match($0,/.*<([0-9]+\.[0-9]+\.[0-9]+)-([0-9]+\.[0-9]+\.[0-9]+)>.*/,line_date); if ( line_date[1] != first_record ) { first_record=line_date[1]; sub(/$/," #1 of "line_date[1]); print; next}; gsub(/\./," ",line_date[1]); gsub(/\./," ",line_date[2]); if ( mktime(line_date[1]" "line_date[2]) > two_days_ago ) { sub(/$/,"+"); print; next}; sub(/$/,"*"); print}' input-file