Multi-line grep entre duas tags, mostra apenas a última correspondência

4

Estou tendo um programa que mistura segmentos de dados na saída de log:

log message
log message
----BEGIN INLINE DATA----
data
data
data
-----END INLINE DATA-----
log messge

Estou procurando algo como

awk '/-BEGIN INLINE DATA-/,/-END INLINE DATA-/'

mas só deve imprimir o último segmento de dados e sem as "tags" ao redor.

    
por awkward_grep 20.10.2013 / 04:54

5 respostas

2

Com o awk, comece a acumular dados após um marcador de início e pare quando encontrar um marcador final. Reinicialize o acumulador de dados se você encontrar um novo marcador de início.

awk '
    /-BEGIN INLINE DATA-/ {data = ""; storing = 1}
    /-END INLINE DATA-/ {storing = 0}
    storing {data = data "\n" $0}
    END {print data}
'
    
por 20.10.2013 / 14:48
1

Você pode canalizar dois seds assim:

<your program> | tac | sed '1,/END INLINE DATA/d' | sed '/BEGIN INLINE DATA/,$d' | tac
    
por 20.10.2013 / 05:04
0
tac log.txt | sed '1,/END INLINE DATA/d' | sed '/BEGIN INLINE DATA/,$d' | tac

parece fazer o trabalho

    
por 20.10.2013 / 05:11
0

Você pode usar este comando para conseguir o que deseja:

$ sed -n '/BEGIN/,/END/p' < data.txt | sed '1d;$d' | tail -1
data

Detalhes

O comando sed imprime todas as linhas (inclusive) entre as linhas BEGIN e END. O segundo comando sed retira a primeira e a última linha, enquanto o comando tail retorna a última linha.

Alternativas

Você também pode usar facilmente sua linha awk :

$ awk '/-BEGIN INLINE DATA-/,/-END INLINE DATA-/'  data.txt | sed '1d;$d' | tail -1
data
    
por 20.10.2013 / 05:12
0

Aqui está uma maneira pouco ortodoxa de fazer isso em Perl:

perl -ne '
  BEGIN{ $/="----BEGIN INLINE DATA----\n" } # Set input record separator

  $payload= s/----END INLINE DATA----.*\z//rs; # Remove end marker and messages

  END{ print $payload } # Print the last payload

' file

Isso requer o Perl v5.14 ou superior. Se você estiver preso a uma versão mais antiga do Perl, precisará de uma linha extra:

perl -ne '
  BEGIN{ $/="----BEGIN INLINE DATA----\n" } # Set input record separator

  $payload= $_; # Copy current line into $payload
  $payload=~ s/----END INLINE DATA----.*\z//s; # Remove end marker and messages

  END{ print $payload } # Print the last payload

' file
    
por 20.10.2013 / 21:57

Tags