Como faço para mover um pedaço de dados entre duas palavras se os dados tiverem um símbolo de% por cento no começo?

1

Eu tenho um arquivo de log parecendo algo como:

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-RTP-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-Control-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#
 policy-map AutoQoS-Police-CiscoPhone
SWEs-elmPCI-A-01(config-pmap)#

Agora eu tenho que procurar todas as linhas que começam com % símbolo entre as linhas que contêm hash # e colocá-lo em outro arquivo de log de erros.

Se você considerar o acima, isso deve entrar no arquivo de log de erros.

   SWEs-elmPCI-A-01(config)#
     class AutoQoS-VoIP-RTP-Trust
                                   ^
    % Invalid input detected at '^' marker.

    SWEs-elmPCI-A-01(config)#
     class AutoQoS-VoIP-Control-Trust
                                   ^
    % Invalid input detected at '^' marker.

    SWEs-elmPCI-A-01(config)#
    
por munish 26.03.2013 / 10:51

2 respostas

1

Talvez algo como:

sed 'H;/#$/!d;s/^/\
/;x;/\n%/!d;s/.//;x;s/.*//;x'

Como você deseja o prompt antes do erro e após o erro, esse inclui os dois, exceto os prompts que, caso contrário, apareceriam como o prompt após um erro e o anterior ao próximo erro para corresponder à saída de amostra.

É muito mais simples incluir os dois prompts, independentemente de os erros se seguirem ou não:

sed 'H;/#$/!d;x;/\n%/!d'

Se você quisesse apenas o prompt antes do erro, isso também seria muito mais simples:

sed '/#$/!{H;d;}
     x;/\n%/!d'

Provavelmente, a melhor maneira de explicar isso é traduzir para uma linguagem mais detalhada como perl . Em sed , o espaço de espera é como uma variável estática que é inicializada com uma linha vazia e o espaço de padrão é uma variável que sed atribui, por sua vez, a cada linha de entrada. Algo como:

$hold_space = "\n";
LINE: while ($pattern_space = <>) {

  <sed commands go here>

  print $pattern_space; # unless -n option is passed
}

O comando H é traduzido para:

$hold_space .= $pattern_space;

O comando d é traduzido para:

next LINE;

Isso é parar de executar os comandos, descartar o espaço padrão e começar de novo com a próxima linha de entrada.

x troca o padrão e armazena o espaço:

($pattern_space, $hold_space) = ($hold_space, $pattern_space);

Para que o último comando sed seja traduzido para:

$hold_space = "\n";
LINE: while ($pattern_space = <>) {

  if (! ($pattern_space =~ /#$/)) { # anything other than a prompt
    $hold_space .= $pattern_space;
    next LINE;
  }

  ($pattern_space, $hold_space) = ($hold_space, $pattern_space);

  if (! ($pattern_space =~ /\n%/)) {
    next LINE;
  }

  print $pattern_space;
}

Que pode ser reescrito de uma forma mais legível como:

LINE: while ($pattern_space = <>) {

  if ($pattern_space =~ /#$/)) {
    if ($hold_space =~ /\n%/)) {
      print $hold_space;
    }
    $hold_space = $pattern_space;
  } else {
    $hold_space .= $pattern_space;
  }
}

Renomeie $pattern_space para $line e $hold_space para $current_block e fique ainda mais legível.

    
por 26.03.2013 / 15:56
2

Não tenho certeza se é isso que você quer, mas:

#!/bin/bash

awk '
BEGIN {
    err=0
}
/^SWE.*#$/ {
    if (err) {
        printf "%s\n%s", txt, $0
        txt=""
        err=0
    } else {
        txt=$0
    }
    next
}
/^% Invalid/ {
    err=1
    txt=txt "\n" $0
    next
}
{
    txt=txt "\n" $0
}
END {
    print ""
}
' "$1"

Resultado:

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-RTP-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-Control-Trust
                               ^
% Invalid input detected at '^' marker.

SWEs-elmPCI-A-01(config)#

Como alternativa, como eu pensei que era com linhas extras para agrupar:

awk '
BEGIN {
    i = 0
    sep="------------------------------------------------"
}
/^% Invalid/ {
    printf "%s %3d\n%s\n%s\n%s\n",
    sep, ++i, txt, $0, sep
    txt=""
    next
}
/^SWE.*#$/ {

    txt=$0
    next
}
txt != "" {
    txt=txt "\n" $0
}
' "$1"

Resultado:

------------------------------------------------   1
SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-RTP-Trust
                               ^
% Invalid input detected at '^' marker.
------------------------------------------------
------------------------------------------------   2
SWEs-elmPCI-A-01(config)#
 class AutoQoS-VoIP-Control-Trust
                               ^
% Invalid input detected at '^' marker.
------------------------------------------------
    
por 26.03.2013 / 11:50