J'ai un gros fichier texte (presque 3 Go) - c'est un fichier journal. Je souhaite obtenir des lignes de texte correspondant à une plage de dates de ce fichier, du 13 au 19 juillet. Mon format de journal est:
2016-07-12 < ?xml version>
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
2016-07-20 < ?xml version>
sample text sample text
sample text sample text
sample text sample text
2016-07-20 < ?xml version>
sample text sample text
2016-07-20 < ?xml version>
ainsi, après grep
name __/sed
il devrait sortir comme ceci:
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
Comment puis-je l'obtenir?
Avec grep
si vous connaissez le nombre de lignes souhaité, vous pouvez utiliser l'option de contexte -A
pour imprimer les lignes après le motif.
grep -A 3 2016-07-13 file
cela vous donnera la ligne avec 2013-07-13 et les 3 prochaines lignes
avec sed
vous pouvez utiliser les dates pour les délimiter comme ceci
sed -n '/2016-07-13/,/2016-07-19/p' file
qui imprimera toutes les lignes de la première ligne avec 2016-07-13 jusqu'à la première ligne incluse avec 2016-07-19. Mais cela suppose que vous n’ayez qu’une ligne avec le 19-07-2016 (la ligne suivante ne sera pas imprimée). S'il y a plusieurs lignes, utilisez plutôt la date suivante et utilisez d
pour en supprimer le résultat.
sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file
Ce simple paquebot grep suffira:
grep -E ^2016-07-1[3-9] filename
Fonctionne bien ici et il n'y a pas besoin de sed :)
Références:
awk
solution:
$ awk '/^2016-07-13.*/,/2016-07-19.*/' input.txt
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
Imprime essentiellement n'importe quelle ligne de celle qui commence par 2016-07-13
à celle qui commence par 2016-07-19
Toutes les autres réponses actuelles reposent sur le fait que les entrées du fichier journal sont triées par ordre chronologique ou sur le fait que la plage de dates peut facilement correspondre à des expressions régulières. Si vous voulez une solution plus générique, nous devons faire plus de programmation.
Je présente ce script GNU AWK:
#!/usr/bin/gawk -f
BEGIN {
starttime = mktime(starttime)
endtime = mktime(endtime)
}
func in_range(n, start, end) {
return start <= n && n < end
}
match($0, /^([0-9]{4})-([0-9]{2})-([0-9]{2})\s/, m) &&
in_range(mktime(m[1] " " m[2] " " m[3] " 00 00 00"), starttime, endtime)
Vous fournissez les heures de début et de fin par le biais des variables starttime
et endtime
dans un format mktime
NAME _ comprend (YYYY MM DD hh dd ss
). Ainsi, vous exécutez la commande awk
comme suit, en supposant que le script Awk ci-dessus se trouve dans un fichier exécutable filter-log-dates.awk
dans le répertoire de travail en cours et que le fichier journal est mylog.txt
:
./filter-log-dates.awk -v starttime='2016 07 13 00 00 00' -v endtime='2016 07 20 00 00 00' mylog.txt
Notez que l'heure de fin est exclusive , i. e. les enregistrements de journal valides doivent avoir un horodatage avant l'heure de fin.
Si votre format d'horodatage est différent, vous pouvez ajuster l'expression régulière transmise à la fonction match
pour l'adapter.
Vous pouvez le faire par étapes. Trouvez le numéro de la première ligne correspondant à votre motif de départ. Trouvez le numéro de la dernière ligne correspondant à votre motif de fin. Extrayez ensuite le test entre ces deux lignes. Cela peut être fait comme suit.
grep -n 2016-07-13 bigtextfile | head -1
grep -n 2016-07-19 bigtestfile | tail -1
# Say the first number is 1234 and the second 5678, then use...
awk 'NR>=1234 && NR<=5678' bigtestfile > rangeoftext
Cela peut être fait dans une commande awk
mais les étapes peuvent faciliter la tâche. Dans awk, la variable NR correspond au numéro de ligne actuel. Etant donné qu'aucune action n'a été spécifiée après le modèle (NR> = 1234 && NR <= 5678), l'action par défaut consiste à imprimer les lignes comprises dans cette plage.