Como obter texto do intervalo de datas usando o grep / sed em um arquivo de texto grande?

6

Eu tenho um grande texto de arquivo (quase 3 GB) - é um arquivo de log. Desejo obter linhas de texto que correspondam a um intervalo de datas desse arquivo, de 13 de julho a 19 de julho. Meu formato de 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>

então, depois de grep / sed , deve ser produzido assim:

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

Como posso conseguir isso?

    
por corey 20.07.2016 / 10:52

5 respostas

9

Com grep , se você souber o número de linhas desejado, poderá usar a opção de contexto -A para imprimir linhas após o padrão

grep -A 3 2016-07-13 file

que lhe dará a linha com 2013-07-13 e as próximas 3 linhas

com sed você pode usar as datas para delimitar assim

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

que imprimirá todas as linhas da primeira linha com 2016-07-13 até e incluindo a primeira linha com 2016-07-19. Mas isso pressupõe que você tenha apenas uma linha com 2016-07-19 (não imprimirá a próxima linha). Se houver várias linhas, use a próxima data e use d para excluir a saída dela

sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file
    
por Zanna 20.07.2016 / 10:58
10

Este simples liner grep será suficiente:

grep -E ^2016-07-1[3-9] filename

Funciona muito bem aqui e não há necessidade de sed:)

Referências:

por andrew.46 20.07.2016 / 11:32
4

Todas as outras respostas atuais dependem do fato de que as entradas do arquivo de log são classificadas cronologicamente ou o fato de que o intervalo de datas pode ser correspondido facilmente com expressões regulares. Se você quiser uma solução mais genérica, precisamos fazer mais algumas programações.

Eu apresento este 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)

Você fornece as horas de início e término através das variáveis starttime e endtime em um formato que mktime entende ( YYYY MM DD hh dd ss ). Assim, você executa o comando awk , assumindo que o script Awk acima está em um arquivo executável filter-log-dates.awk no diretório de trabalho atual e o arquivo de log é mylog.txt :

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

Note que o horário de término é exclusivo , i. e. registros de log válidos devem ter um registro de data e hora antes da hora de término.

Se o formato do carimbo de data / hora for diferente, você poderá ajustar a expressão regular passada para a função match para adaptá-la.

    
por David Foerster 20.07.2016 / 12:32
3

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> 

Basicamente imprime qualquer linha desde a que começa com 2016-07-13 até aquela que começa com 2016-07-19

    
por Sergiy Kolodyazhnyy 20.07.2016 / 11:50
2

Você pode fazer isso em etapas. Encontre o número da primeira linha correspondente ao seu padrão inicial. Encontre o número da última linha que corresponde ao seu padrão final. Em seguida, extraia o teste entre essas duas linhas. Isso pode ser feito da seguinte maneira.

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

Isso pode ser feito tudo em um comando awk , mas as etapas podem facilitar a sua execução. No awk, a variável NR é o número da linha atual e, como nenhuma ação foi especificada após o padrão (NR > = 1234 & NR < = 5678), a ação padrão é imprimir as linhas nesse intervalo.

    
por Jeffrey Ross 20.07.2016 / 11:33