Filtrar grandes conjuntos de dados em datas com linha de comando

1

Eu tenho um enorme conjunto de dados que consiste em valores separados por tabulações que são armazenados em linhas. Uma linha de exemplo é assim:

Dec 4 14:37:36.381651 algorc1 [27751:l@27932]/error:   [] - [T0000A124M5] Didn't receive message!

Eu quero filtrar todos os messeages antes de um horário específico em uma data específica.

Meus pensamentos são assim:

grep <file> | select everything in first column larger than date | select everything in second column larger than time

Eu só não sei como posso selecionar por coluna e não sei sobre datas e horários maiores e menores.

Então eu não sei muito; -).

    
por seb 08.12.2014 / 16:13

2 respostas

2

Você pode usar sed para filtrá-los. Este exemplo simples pressupõe que você sabe exatamente o horário de início / término:

sed -n '/Dec 4 14:37:36.381651/,/Dec 5 14:32:36.391572/' filename

Você não pode arredondar essas horas / datas para valores que não existem. Por exemplo:

sed -n '/Dec 4 14:30:00.000000/,/Dec 5 14:29:59.999999/' filename

não funcionaria a menos que os horários especificados estivessem no log.

Se você quiser filtrar entre duas horas / datas arbitrárias que não estão no registro, então awk pode ajudar:

awk 'BEGIN {FS=":| +"} {current = mktime("2014 "c($1)" "$2" "$3" "$4" "$5); if (current >= mktime ("2014 12 04 14 30 0") && current <= mktime("2014 12 05 14 29 59")) {print $0 }} function c(s){return(sprintf("%02d\n",(match("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3)) }' filename

A hora / datas selecionadas estão no formato AAAA MM DD HH MM SS. Você também notará que o ano está embutido no código, pois seus registros não contêm o ano - presumo que seja este ano.

O one-liner acima, mas melhor formatado e com comentários:

#!/usr/bin/awk -f
BEGIN {
    # Split line into fields using colon or spaces
    FS=":| +"
}
{
    # Generate the timestamp of the current line from the first 5 fields.
    # Use the function c(), defined below, to convert 3 letter months to numerical
    current = mktime("2014 "c($1)" "$2" "$3" "$4" "$5);
    # If the timestamp of the current line is between two specified
    # timestamps then print the whole line
    if (current >= mktime ("2014 12 08 15 0 0") && current <= mktime("2014 12 08 16 05 00")) 
        {print $0 }
}
function c(s) {
    # Function to convert three letter month to numerical
    # If s == Jan then returns 1. If s == Aug, returns 8
    return(sprintf("%02d\n",(match("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3))
}
    
por 08.12.2014 / 16:42
2

Uma solução, convertendo data para época:

while read month dm hour rest; do
    d=$(date -d"$month $dm $hour" "+%m%d%H%M%S")
    echo "$d $rest"
done < file | awk '$1 < 1204143737' # print all lines before this date
    
por 08.12.2014 / 16:41

Tags