pt - Imprime linhas correspondidas por um intervalo de padrões se uma linha corresponder a uma condição [duplicada]

8

Eu tenho um formato de entrada de log de várias linhas que preciso processar.

O log se parece com algo assim:

--START--
Device=B
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=B
Data=asdfasdf
--END--
--START--
Device=A
Data=asdfasdf
--END--
--START--
Device=B
Data=asdfasdf
--END--
--START--
Device=C
Data=asdfasdf
Lorem=Ipsum
--END--

Eu quero imprimir tudo entre --START-- e --END-- se um padrão específico for correspondido.

por exemplo:

Imprimir todas as entradas em que Device=A

--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
--END--

Tudo o que consegui fazer até agora é escrever:

sed -e -n '/--START--/,/--END--/p' < input

O que efetivamente imprime a entrada, mas acho que preciso adicionar {} para filtrar com N e, em seguida, imprimir se essa condição corresponder.

Eu também acho que estou completamente perdido.

Alguma ideia de como imprimir várias linhas se uma única linha corresponder a uma condição?

    
por Brad 10.09.2015 / 03:54

4 respostas

11
$ sed -n '/--START--/{:a;N;/--END--/!ba; /Device=A/p}' file
--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
--END--

(O acima foi testado no GNU sed. Ele teria que ser massageado para funcionar no BSD / OSX.)

Como funciona:

  • /--START--/{...}

    Sempre que chegarmos a uma linha que contenha --START-- , execute os comandos dentro das chaves {...} .

  • :a

    Defina um rótulo a .

  • N

    Leia a próxima linha e adicione-a ao espaço do padrão.

  • /--END--/!ba

    A menos que o espaço padrão agora contenha --END-- , retorne ao rótulo a .

  • /Device=A/p

    Se chegarmos aqui, isso significa que o espaço dos padrões começa com --START-- e termina com --END-- . Se, além disso, o espaço de padrão contiver Device=A , imprima ( p ).

por 10.09.2015 / 04:31
6

Outro sed variante com uso de espaço de espera

sed 'H              #add line to hold space
     /--START--/h   #put START into hold space (substitute holded in)
     /--END--/!d    #clean pattern space (start next line) if not END
     x              #put hold space into pattern space
     /Device=A/!d   #clean pattern space if it have not "Device=A"
    ' file
    
por 10.09.2015 / 09:21
1

com sed :

$ -e:1 -e'$!N;/--END--/{
  /Device=A/!d
  b
}' -eb1 <file
--START--
Device=A
Data=asdfasdf
Lorem=Ipsum
--END--
--START--
Device=A
Data=asdfasdf
--END--

Isso leu toda a linha entre --START-- e --END-- no espaço padrão. Se corresponder a --END-- , verificamos se o espaço padrão não continha Device=A , excluí-lo, senão sed imprime o espaço padrão e, em seguida, inicia o próximo ciclo.

com awk :

awk '
  /--START--/ {
    getline d
    if (d ~ /Device=A/) {
      p = 1
      printf "%s\n%s\n", $0, d
      next
     }
  }
  p
  /--END--/ { p = 0 }
' <file
    
por 10.09.2015 / 04:33
0

Já existem várias outras boas respostas que demonstram como testar sua string entre blocos --START-- e --END-- , mas, dada sua entrada de exemplo, pode ser que você não precise se preocupar com --START-- .

sed -n '$!N;/^Device=A\n/,/\n--END--/P;D'

... imprimiria tudo de Device=A até o último \n ewline ocorrendo imediatamente antes da próxima ocorrência --END-- em cada bloco. Ele não se preocupa com --START-- porque não parece que é necessário verificar isso.

Então, para um bloco como:

--START--
Device=A
...stuff...
--END--

... a saída seria ...

Device=A
...stuff...

... mas por um bloco como ...

--START--
Device=B
Device=A
...stuff...
--END--

... ele produziria o mesmo.

Funciona acrescentando a linha de entrada N ext a cada linha que é ! e não a $ anterior, e assim o espaço padrão é semelhante:

^line1\nline2$

Para cada espaço de padrão que ocorre entre as seqüências ^Device=A\n e \n--END-- , a primeira das duas linhas atualmente em padrão é P rinted e depois D eliminado antes de iniciar o próximo ciclo com o que resta. E assim o próximo espaço padrão parece ...

^line2\nline3$
    
por 10.09.2015 / 10:03