Como imprimir linhas entre pattern1 e 2nd match de pattern2?

4

O arquivo de teste é fornecido abaixo:

PATTERN1
a
b
c
PATTERN2
d
e
f
PATTERN2
g
h

Quero imprimir a linha entre PATTERN1 e a segunda correspondência de PATTERN2 :

PATTERN1
a
b
c
PATTERN2
d
e
f
PATTERN2
    
por sachin 28.06.2016 / 13:04

4 respostas

6

Aqui está uma maneira de fazer isso com sed :

sed '/PATTERN1/,$!d;/PATTERN2/{x;//{x;q;};g;}' infile

Isso exclui todas as linhas (se houver) até a primeira ocorrência de PATTERN1 e, em seguida, em cada linha que corresponde a PATTERN2 it e x altera os buffers. Se o novo espaço de padrão também coincidir, isso significa que é a segunda ocorrência, portanto, e x é alterado novamente e q uits (após a impressão automática). Se não corresponder, significa que é a primeira ocorrência, copiando o conteúdo do espaço suspenso sobre o espaço padrão por meio de g (agora há uma linha correspondente a PATTERN2 no buffer retido) e continua ...
e outra maneira com awk :

awk '/PATTERN1/{t=1}; t==1{print; if (/PATTERN2/){c++}}; c==2{exit}' infile

Ele começa a imprimir e contar as linhas que correspondem a PATTERN2 somente quando encontra uma linha correspondente a PATTERN1 e sai quando c ounter atinge 2 .

    
por 28.06.2016 / 13:30
5

A ferramenta certa para este trabalho é pcregrep :

pcregrep -M 'PATTERN1(.|\n)*PATTERN2' file

onde a opção -M permite que o padrão corresponda a mais de uma linha e (.|\n)* corresponda a qualquer caractere ou nova linha zero ou mais vezes.

Observe que aproveitamos a ganância do grep. Se você quiser imprimir o padrão de formulário1 até a ocorrência primeiro do padrão2, o *? não-ganancioso deve ser usado em vez de * .

Como uma generalização, para imprimir até a n th ocorrência de PATTERN2:

pcregrep -M 'PATTERN1((.|\n)*?PATTERN2){n}' file

Altere n para o número real necessário.

    
por 28.06.2016 / 13:43
5

Use apenas sinalizadores:

$ awk '/PATTERN1/{flag=2;next} flag; /PATTERN2/{flag--}' file
a
b
c
PATTERN2
d
e
f
PATTERN2

Ou seja: quando você encontrar PATTERN1 , defina o sinalizador como um valor positivo; em particular, 2. Então, quando você encontrar PATTERN2 , diminua esse sinalizador em um. Desta forma, irá esgotar após o segundo jogo. No meio, use flag como um valor que aciona o {print $0} quando tiver um valor verdadeiro (2 ou 1).

    
por 28.06.2016 / 15:11
2

Se dissermos que sed é muito fácil de coletar linhas desnecessárias, imprima

sed -n '
    /PATTERN1/{
        :1
        $!N
        /\(PATTERN2\).*/!b1
        p
    }
' file
    
por 28.06.2016 / 15:23