Substituindo um padrão na linha precedendo outro padrão de interesse

3

Eu tenho um arquivo de log com muitas instâncias de instruções, conforme mostrado abaixo:

14 Aug 19 16:30:11.506: <DATA>  |POS|IDLE|1|01131844090|5950|$hostIp|$size  |$data
20 Aug 19 16:30:12.439: <DATA>  |POS|IDLE|1|01131844090|5950|$hostIp|$size  |$data
21 ###############################################################################

Eu quero substituir IDLE antes do #########.. , END e ter outros casos de IDLE retidos.

Como faço para isso?

Editar:    Talvez algo seja diferente com o meu arquivo atual. Respostas a esta pergunta não cumpriram o requisito. Extrato detalhado e minha exigência é mostrada abaixo:

  22 Aug 19 16:47:33.159: <DATA>  |POS|RINGING|1|1126710938|5950|$hostIp|$size  |$data
    23 Aug 19 16:47:33.453: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
    24 Aug 19 16:47:33.484: <DATA>  |POS|TRAINING|1|1126710938|5950|$hostIp|$size  |$data
    25 Aug 19 16:48:05.824: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
    26 Aug 19 16:48:05.916: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
    27 Aug 19 16:48:05.947: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
    28 Aug 19 16:48:23.792: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
    29 Aug 19 16:48:23.853: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
    30 Aug 19 16:48:23.884: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
    31 ##############################################################################

Depois de operar na instância acima, o resultado deve ser: ( IDLE anterior à linha #### foi alterada para END .Não há muitas instâncias de tais eventos. Minha necessidade real é encontrar o tempo entre RINGING e IDLE - aka END)

22 Aug 19 16:47:33.159: <DATA>  |POS|RINGING|1|1126710938|5950|$hostIp|$size  |$data
23 Aug 19 16:47:33.453: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
24 Aug 19 16:47:33.484: <DATA>  |POS|TRAINING|1|1126710938|5950|$hostIp|$size  |$data
25 Aug 19 16:48:05.824: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
26 Aug 19 16:48:05.916: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
27 Aug 19 16:48:05.947: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
28 Aug 19 16:48:23.792: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
29 Aug 19 16:48:23.853: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
30 Aug 19 16:48:23.884: <DATA>  |POS|END|1|1126710938|5950|$hostIp|$size  |$data
31 ##############################################################################
    
por Prabhu 08.09.2014 / 12:00

3 respostas

2

Atualizar : o modo de comando ex funcionará apenas na primeira linha correspondente. O exemplo de perl substituirá todas as linhas com o padrão, mas somente fornecerá a saída e não editará o arquivo original, portanto, será necessário redirecionar a saída para um novo arquivo. YOUR-LOGFILE deve ser substituído pela localização do arquivo que você está tentando modificar.

perl -0pe 's/IDLE(.*\n.*###)/END/g' YOUR-LOGFILE > NEWFILE

Isso substituirá a linha logo acima da linha que contém o padrão e, em seguida, sairá.

ex -s +'/######/-1 s/IDLE/END/ | x' YOUR-LOGFILE

    
por 08.09.2014 / 12:42
2

Tente:

$ awk '!/^#+$/ {print l; l=$0; next} {gsub("IDLE","END",l); print l; l=$0} END {print $0}' < log.txt

que dá:

Aug 19 16:30:11.506: <DATA>  |POS|IDLE|1|01131844090|5950|$hostIp|$size  |$data
Aug 19 16:30:12.439: <DATA>  |POS|END|1|01131844090|5950|$hostIp|$size  |$data
###############################################################################
    
por 08.09.2014 / 12:56
1
sed '$!N;/###$/s/IDLE/END/;P;D
' <<\DATA
22 Aug 19 16:47:33.159: <DATA>  |POS|RINGING|1|1126710938|5950|$hostIp|$size  |$data
23 Aug 19 16:47:33.453: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
24 Aug 19 16:47:33.484: <DATA>  |POS|TRAINING|1|1126710938|5950|$hostIp|$size  |$data
25 Aug 19 16:48:05.824: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
26 Aug 19 16:48:05.916: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
27 Aug 19 16:48:05.947: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
28 Aug 19 16:48:23.792: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
29 Aug 19 16:48:23.853: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
30 Aug 19 16:48:23.884: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
31 ##############################################################################
DATA

Que expande o buffer de uma linha normal de sed para um buffer de duas linhas. Em cada linha, exceto a última, ela anexa a próxima linha de entrada ao espaço padrão. Se o buffer de duas linhas terminar com a string ### , ele substitui a primeira string IDLE com END . Então, P envia até a primeira nova linha que está ocorrendo no buffer e D é igual antes de recomeçar com o que resta. É uma solução extremamente simples, POSIX-portátil e muito rápida para o seu problema.

OUTPUT

22 Aug 19 16:47:33.159: <DATA>  |POS|RINGING|1|1126710938|5950|$hostIp|$size  |$data
23 Aug 19 16:47:33.453: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
24 Aug 19 16:47:33.484: <DATA>  |POS|TRAINING|1|1126710938|5950|$hostIp|$size  |$data
25 Aug 19 16:48:05.824: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
26 Aug 19 16:48:05.916: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
27 Aug 19 16:48:05.947: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
28 Aug 19 16:48:23.792: <DATA>  |POS|IDLE|1|1126710938|5950|$hostIp|$size  |$data
29 Aug 19 16:48:23.853: <DATA>  |POS|INIT|1|1126710938|5950|$hostIp|$size  |$data
30 Aug 19 16:48:23.884: <DATA>  |POS|END|1|1126710938|5950|$hostIp|$size  |$data
31 ##############################################################################

Para editar um arquivo no local de forma portável, você pode fazer:

 sed '$!N;/###$/s/IDLE/END/;P;D
 ' <<FILE >file
 $(cat file)
 FILE

Ou então, com o GNU sed , pelo menos, você pode fazer:

 sed -i '$!N;/###$/s/IDLE/END/;P;D' file
    
por 08.09.2014 / 16:17