Estou escrevendo um script ksh para analisar um arquivo de log e enviar um e-mail quando forem encontradas mensagens importantes. Algumas mensagens são informativas e gostaria de ignorá-las.
O arquivo de log tem formato
2018-01-24.08.24.35.875675 some text
more text
more text
more text
more text
2018-01-24.08.24.37.164538 some text
more text
more text
INF9999W <-- informational text
more text
2018-01-24.08.24.46.8602545 some text
more text
more text
more text
O timestamp seria considerado o separador da mensagem, sendo o timestamp pertencente à mensagem que o segue. Eu gostaria de pesquisar o arquivo para cada ocorrência de "texto de informação" e, em seguida, remover toda a mensagem do arquivo (do carimbo de data / hora anterior até pouco antes do próximo carimbo de data / hora).
Como posso determinar facilmente os números de linha dos timestamps anteriores e seguintes para remover essas linhas com:
awk 'NR<'$preceding_ts' || NR >='$following_ts'
Minha maneira é colocar todas as linhas de carimbo de data/hora em um arquivo e, em seguida, percorrer esse arquivo até encontrar as linhas de carimbo de data/hora que estão logo antes e depois da linha # de 'texto de informação'. Parece muito trabalho, especialmente em um arquivo grande. Existe uma maneira mais eficiente.
integer inf_line
integer last_ts_line
integer cur_ts
cp $error_log $copy_log
while true
do
inf_line=$(grep -n "INF99999W" $copy_log | head -1 | cut -f1 -d":")
if [[ $inf_line -eq 0 ]]
then
break
fi
grep -n -E "^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]-" $copy_log | cut -f1 -d":" > $ts_lines
last_ts_line=99999999
cat $ts_lines | while read cur_ts
do
if [[ $cur_ts -gt $inf_line && $last_ts_line -lt $inf_line ]]
then
awk 'NR<'$last_ts_line' || NR >='$cur_ts'' $copy_log > $temp_log
cp $temp_log $copy_log
last_ts_line=$cur_ts
break
fi
last_ts_line=$cur_ts
done
if [[ $last_ts_line -lt $inf_line ]]
then
awk 'NR<'$last_ts_line'' $copy_log > $temp_log
cp $temp_log $copy_log
fi
done
Obrigado.
Eu iria abordá-lo armazenando as linhas da mensagem atual e, quando a mensagem terminasse, imprimindo o lote armazenado se nenhum
INF
marcador fosse visto. Aqui,d
contém as linhas da mensagem atual (d para dados),p
informa se queremos imprimir as linhas armazenadas ou não.A primeira regra aqui corresponde às linhas de registro de data e hora, imprime todas as linhas armazenadas se
p
for verdadeira, armazena esta linha e definep
como um. A segunda regra é redefinidap
para zero se uma linha com oinfo
padrão for vista; o padrão é definido para a variável com-vinfo=...
. A terceira regra anexa a linha atual às coletadas eEND
, novamente, a regra apenas imprime as linhas coletadas, sep
estiver definida.Também poderíamos escrever assim, isso verificaria o
info
padrão também na linha do carimbo de data/hora:Em geral, é provavelmente uma boa ideia escrever coisas como esta em
awk
Perl. O resultado será pelo menos muito mais rápido de rodar do que um shell script que bifurca dezenas de cópias degrep
,awk
, ecut
etc...