web-dev-qa-db-fra.com

Comment obtenir du texte à partir d'une plage de dates en utilisant grep / sed dans un grand fichier texte?

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 grepname __/sedil 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?

7
corey

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
11
Zanna

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:

10
andrew.46

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

4
Sergiy Kolodyazhnyy

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 starttimeet endtimedans un format mktimeNAME _ comprend (YYYY MM DD hh dd ss). Ainsi, vous exécutez la commande awkcomme 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 matchpour l'adapter.

4
David Foerster

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.

3
Jeffrey Ross