Como selecionar a primeira ocorrência entre dois padrões, incluindo eles

27

Como posso selecionar a primeira ocorrência entre dois padrões, incluindo eles. De preferência, usando sedou awk.

Eu tenho:

text
something P1 something
content1
content2
something P2 something
text
something P1 something
content3
content4
something P2 something
text

Quero a primeira ocorrência das linhas entre P1 e P2 (incluindo a linha P1 e a linha P2):

something P1 something
content1
content2
something P2 something
kofucii
fonte

Respostas:

22
sed '/P1/,/P2/!d;/P2/q'

... dexecutaria o trabalho de maneira portável , excluindo todas as linhas que !não se enquadram no intervalo e, em seguida, qacionando a primeira vez que encontrar o final do intervalo. Ele não falha no P2 anterior ao P1 e não requer que a sintaxe específica do GNU escreva com simplicidade.

mikeserv
fonte
Excelente! Muito melhor que o meu.
muru
1
@muru - Geralmente, é mais fácil evitar contorções se você tentar direcionar a impressão automática - deixe o ciclo funcionar para você. Esse é o hábito que eu caí de qualquer maneira. Eu acho que provavelmente é melhor descrito como uma ameixa versus um método de seleção - eu costumo acabar negando um padrão em vez de procurá-lo.
mikeserv
Isso será interrompido ao processar um enorme tamanho de arquivo.
Brain90
@ Brain90 - não deveria. se você pode reproduzir sua reclamação de maneira confiável, deve dirigir-se ao mantenedor do seu sed... isso é um bug na sedexecução e não no script acima.
precisa saber é o seguinte
1
@ MikeServ Eu não teria dito isso se não estivesse. Sua preocupação sobre se me importo ou não com alguns personagens é estranha: observei que a expressão sed funcionava com e sem /P2/qno meu sistema; é isso aí. Eu estava curioso sobre alguma coisa e queria compartilhar o que encontrei.
Alexej Magura 10/10
8

com awk

awk '/P1/{a=1};a;/P2/{exit}' file
something P1 something
content1
content2
something P2 something
iruvar
fonte
8

Em sed:

sed -n '/P1/,/P2/p; /P2/q'
  • -nsuprime a impressão padrão e você imprime linhas entre os intervalos de endereços correspondentes usando o pcomando
  • Normalmente, isso corresponderia às duas seções, então você sai ( q) quando a primeira P2correspondência.

Isso falhará se um P2vier antes P1. Para lidar com esse caso, tente:

sed -n '/P1/,/P2/{p; /P2/q}'
muru
fonte
1
Discordo; A resposta de mikeserv não é melhor que a sua.
G-Man diz 'Reinstate Monica'
@ g-man - pshaw. mas eu estava pensando a mesma coisa.
mikeserv 25/08
1
@gman - não. agora eu entendi. minas muito melhor. não {pilha}!
mikeserv 23/10
1

Se você quiser pular os padrões, aqui está a awkversão:

awk '/P2/ {exit} /P1/ {f=1; next} f' file
codeforester
fonte
Funciona para mim. Você poderia adicionar mais algumas informações sobre como o comando funciona?
0xAffe
1

Uma awksolução mais simples (meio caminho entre a resposta do iruvar e  a resposta do muru , mas sem usar uma variável):

awk '/P1/,/P2/ { print }  /P2/ { exit }'

e, como muru observou, se o primeiro P2 aparecer antes do primeiro P1, isso não imprimirá nada.

Obviamente, se você deseja imprimir todos os intervalos P1-P2:

something P1 something
content1
content2
something P2 something
something P1 something
content3
content4
something P2 something

apenas deixe de fora a exitparte:

awk '/P1/,/P2/ { print }'
G-Man Diz 'Reinstate Monica'
fonte
1
awk '/P1/,/P2/{print;f=1} f&&/P2/{exit}' data

Saia imediatamente após a impressão, não antes.

dedowsdi
fonte
0

Para ignorar os próprios padrões e mostrar apenas o primeiro bloco correspondente no único GNU sed:

sed -nre '/STARTPATTERN/ {:a;n;/ENDPATTERN/{b;};p;ba}' file
Santrix
fonte