Come ottenere testo da un intervallo di date usando grep / sed in file di testo di grandi dimensioni?


9

Ho un testo di file di grandi dimensioni (quasi 3 GB): è un file di registro. Voglio ottenere righe di testo che corrispondono a un intervallo di date da questo file, dal 13 luglio al 19 luglio. Il mio formato di registro è:

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>

quindi dopo grep/ seddovrebbe essere prodotto in questo modo:

2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>

Come posso ottenerlo?


2
Sei sicuro di voler dire giugno ? Tutte le date nel file di registro di esempio sono in luglio e l'esempio di output desiderato implica che intendevi quest'ultima.
David Foerster,

Risposte:


13

Con grepse si conosce il numero di righe che si desidera è possibile utilizzare l'opzione contesto -Aper stampare le linee secondo il modello

grep -A 3 2016-07-13 file

che ti darà la linea con 2013-07-13 e le prossime 3 linee

con sedte puoi usare le date per delimitare in questo modo

sed -n '/2016-07-13/,/2016-07-19/p' file

che stamperà tutte le righe dalla prima riga con 13/07/2016 fino alla prima riga inclusa con 19/07/2016. Ma questo presuppone che tu abbia solo una riga con 19/07/2016 (non stamperà la riga successiva). Se sono presenti più righe, utilizzare invece la data successiva e utilizzare dper eliminare l'output da essa

sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file


4

awk soluzione:

$ 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> 

Fondamentalmente stampa qualsiasi linea da quella che inizia con 2016-07-13a quella che inizia con2016-07-19


4

Tutte le altre risposte correnti si basano sul fatto che le voci del file di registro sono ordinate in ordine cronologico o sul fatto che l'intervallo di date può essere facilmente associato alle espressioni regolari. Se vuoi una soluzione più generica, dobbiamo fare un po 'più di programmazione.

Vi presento questo 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)

Fornisci l'ora di inizio e di fine attraverso le variabili starttimee endtimein un formato che mktimecapisca ( YYYY MM DD hh dd ss). Quindi si esegue il awkcomando in questo modo, supponendo che lo script Awk sopra sia in un file eseguibile filter-log-dates.awknella directory di lavoro corrente e il file di registro sia mylog.txt:

./filter-log-dates.awk -v starttime='2016 07 13 00 00 00' -v endtime='2016 07 20 00 00 00' mylog.txt

Si noti che l'ora di fine è esclusiva , ovvero i record di registro validi devono avere un timestamp prima dell'ora di fine.

Se il formato del timestamp è diverso, è possibile regolare l'espressione regolare passata alla matchfunzione per adattarla.


3

Potresti farlo in pochi passaggi. Trova il numero della prima riga corrispondente al modello iniziale. Trova il numero dell'ultima riga corrispondente al modello finale. Quindi estrarre il test tra queste due righe. Questo può essere fatto come segue.

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

Questo potrebbe essere fatto tutto in un awkcomando, ma i passaggi potrebbero renderlo più facile da seguire. All'interno di awk la variabile NR è il numero di riga corrente e poiché nessuna azione è stata specificata dopo il modello (NR> = 1234 && NR <= 5678), l'azione predefinita è stampare le linee che in quell'intervallo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.