Correspondência com vários padrões e impressão em uma única linha

2

Eu preciso combinar dois padrões em um arquivo de log e preciso obter a próxima linha do padrão (de dois padrões) correspondente, finalmente precisa imprimir esses três valores em uma única linha.

Arquivo de registro de amostra:

2013/09/05 04:26:00          Processing Batch /fbc/dev/cebi/dod/9739867262
2013/09/05 04:26:02          Batch 9739867262 was successful
2013/09/05 04:26:02          Total Time          =  3.13 Secs
2013/09/05 04:26:02          Repository API Time =  2.96 Secs
2013/09/05 04:26:02          File System Io Time =  0.06 Secs
2013/09/05 04:26:02          Doc Validation Time =  0.03 Secs
2013/09/05 04:26:02      Ending @ Thu Sep 05 04:26:02 EDT 2013
2013/09/05 08:18:10      Starting @ Thu Sep 05 08:18:10 EDT 2013
2013/09/05 08:18:10      Starting @ Thu Sep 05 08:18:10 EDT 2013
2013/09/05 08:18:10          Processing Batch /fbc/dev/cebi/dod/9844867675
2013/09/05 08:18:10          Processing Batch /fbc/dev/cebi/dod/9886743777
2013/09/05 08:18:16          Batch 9844867675 was successful
2013/09/05 08:18:16          Total Time          =  6.00 Secs
2013/09/05 08:18:16          Repository API Time =  5.63 Secs
2013/09/05 08:18:16          File System Io Time =  0.05 Secs
2013/09/05 08:18:16          Doc Validation Time =  0.19 Secs
2013/09/05 08:18:16      Ending @ Thu Sep 05 08:18:16 EDT 2013
2013/09/05 08:18:18          Batch 9886743777 was successful
2013/09/05 08:18:18          Total Time          =  8.27 Secs
2013/09/05 08:18:18          Repository API Time =  8.52 Secs
2013/09/05 08:18:18          File System Io Time =  0.08 Secs
2013/09/05 08:18:18          Doc Validation Time =  0.47 Secs
2013/09/05 08:18:18      Ending @ Thu Sep 05 08:18:18 EDT 2013

Eu tenho os números separados no arquivo chamado cust_no.txt

9739867262
9844867675
9886743777

Tendo esses números como entrada, preciso corresponder aos dois padrões a seguir no arquivo de log

  1. Processamento de lote / fbc / dev / cebi / dod /
  2. O lote foi bem sucedido

Os seguintes são obrigatórios como saída:

- > Na partida do primeiro padrão ( i.e Processing Batch /fbc/dev/cebi/dod/<numbers in the cust_no.txt> ) eu preciso pegar a segunda palavra, ou seja, $ 2. - > No jogo dos segundos padrões ( i.e Batch <numbers in the cust_no.txt> was successful ) eu preciso pegar a segunda palavra, ou seja, $ 2 - > E a sexta palavra ($ 6) na próxima linha após a partida após o segundo padrão (ou seja, a linha que está olhando com Total Time )

Saída desejada:

9739867262,04:26:00,04:26:02,3.13 Secs
9844867675,08:18:10,08:18:16,6.00 Secs
9886743777,08:18:10,08:18:18,8.27 Secs

Para conseguir isso eu tentei da maneira abaixo, mas isso parece não funcionar:

awk -v cn=$cust_no '{{if ($0 ~ "Processing.*" cn) st=$2 && if ($0 ~ "Customer cn was successful" et=$2; getline; tt=$4} ; print st,et,tt}
    
por Ram 17.10.2013 / 21:46

3 respostas

2

Que tal isso:

while read number;do
    start=$(grep "Processing Batch /fbc/dev/cebi/dod/$number" log_file\
            |head -n 1|awk '{print $2}')
    end=$(grep -A 1 "Batch $number was successful" log_file\
            |head -n 2|tail -n 1|awk -v OFS=',' '{print $2,$6}')
    echo "$number,$start,$end Secs"
done <cust_no.txt
    
por 20.10.2013 / 22:25
1

Se você não se importa em usar o Perl & grep aqui está uma solução para o seu problema. Aqui está o script, chamado cmd.pl :

#!/usr/bin/env perl

use feature 'say';
#use Data::Dumper;

@file = 'grep -f cust_no.txt -A 1 sample.log';

my (%info, $secLineSeen, $time, $custno);

$secLineSeen = 0;
foreach my $line (@file) {
    if ($secLineSeen == 1) {
        #2013/09/05 08:18:18          Total Time          =  8.27 Secs
        (my $totTime) = ($line =~ m!\S+ \S+\s+Total Time\s+=\s+(\S+ Secs)!);
        $info{$custno}{totTime} = $totTime;
        $secLineSeen = 0;

    } elsif ($line =~ m/Processing Batch/) {
        #2013/09/05 08:18:10          Processing Batch /fbc/dev/cebi/dod/9844867675
    ($time, $custno) = ($line =~ m!\S+ (\S+)\s+Processing Batch.*/(\S+)!);
        $info{$custno}{onetwo} = $time;

  } elsif ($line =~ m/Batch.*successful/) {
        #2013/09/05 08:18:18          Batch 9886743777 was successful
        ($time, $custno) = ($line =~ m!\S+ (\S+)\s+Batch (\S+) was.*!);
        $info{$custno}{twotwo} = $time;
        $secLineSeen = 1;
    }
}

#print Dumper(\%info);

#9739867262,04:26:00,04:26:02,3.13 Secs
foreach my $key (sort keys %info) {
    say "$key,$info{$key}{onetwo},$info{$key}{twotwo},$info{$key}{totTime}";
}

Exemplo

$ ./cmd.pl 
9739867262,04:26:00,04:26:02,3.13 Secs
9844867675,08:18:10,08:18:16,6.00 Secs
9886743777,08:18:10,08:18:18,8.27 Secs

Detalhes

Este script Perl cria primeiro uma matriz, @file , que contém os resultados deste comando:

$ grep -f cust_no.txt -A 1 sample.log

Esse comando pega o arquivo de log, sample.log , e seleciona todas as linhas que contêm números de clientes do arquivo cust_no.txt , assim:

2013/09/05 04:26:00          Processing Batch /fbc/dev/cebi/dod/9739867262
2013/09/05 04:26:02          Batch 9739867262 was successful
2013/09/05 04:26:02          Total Time          =  3.13 Secs
--
2013/09/05 08:18:10          Processing Batch /fbc/dev/cebi/dod/9844867675
2013/09/05 08:18:10          Processing Batch /fbc/dev/cebi/dod/9886743777
2013/09/05 08:18:16          Batch 9844867675 was successful
2013/09/05 08:18:16          Total Time          =  6.00 Secs
--
2013/09/05 08:18:18          Batch 9886743777 was successful
2013/09/05 08:18:18          Total Time          =  8.27 Secs

Esse comando grep faz uma coisa extra especial que vale a pena mencionar, principalmente porque mantém uma linha adicional após ( -A 1 ) qualquer correspondência. Isso nos permite pegar a linha com o "Tempo Total".

Quando esses dados forem extraídos, o script Perl usará um hash multidimensional para armazenar os resultados das principais partes de dados dessa saída, de acordo com os requisitos mencionados na pergunta.

O hash se parece com isso assim que terminamos de processar o conteúdo de @file :

$VAR1 = {
          '9739867262' => {
                            'twotwo' => '04:26:02',
                            'totTime' => '3.13 Secs',
                            'onetwo' => '04:26:00'
                          },
          '9886743777' => {
                            'twotwo' => '08:18:18',
                            'totTime' => '8.27 Secs',
                            'onetwo' => '08:18:10'
                          },
          '9844867675' => {
                            'twotwo' => '08:18:16',
                            'totTime' => '6.00 Secs',
                            'onetwo' => '08:18:10'
                          }
        };

Finalmente, percorremos esse hash e imprimimos o conteúdo que coletamos, no formato especificado na pergunta.

    
por 20.10.2013 / 22:08
0

Eu tentaria grep nisso:

grep -EA 1 'pattern1|pattern2' file.log

Use a opção -E para regex estendido e -A para o número de linhas a seguir. Agora, para imprimir isso em uma linha, posso pensar em uma maneira muito hackeada usando o sed:

grep -EA 1 'pattern1|pattern2' file.log | grep -v ^-- | sed 'N ; s+\n+|+g'

Passar o comando N (ler próxima linha) para sed permite processar duas linhas de entrada de cada vez. Por outro lado, o comando s+\n+|+g permite substituir (com um caractere divisor de sua escolha) ou excluir (se a substituição estiver vazia) a nova linha entre as duas linhas sendo processadas, deixando apenas a nova linha no final de a segunda linha.

grep -v ^-- é necessário para eu me livrar da saída -- pela primeira instância do grep (veja o exemplo ilustrativo abaixo).

Line 1
Line 2
--
Line X
Line Y
    
por 18.10.2013 / 02:11