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

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.


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

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}'

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

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 }'

1
awk '/P1/,/P2/{print;f=1} f&&/P2/{exit}' data

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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.