Cómo seleccionar la primera aparición entre dos patrones, incluidos ellos


27

¿Cómo puedo seleccionar la primera aparición entre dos patrones, incluidos ellos? Preferiblemente usando sedo awk.

Yo tengo:

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

Quiero la primera aparición de las líneas entre P1 y P2 (incluidas la línea P1 y la línea P2):

something P1 something
content1
content2
something P2 something

Respuestas:


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

... haría el trabajo de forma portátil deligiendo todas las líneas que no !se encuentren dentro del rango, y luego se qapaga la primera vez que encuentra el final del rango. No falla para P2 que precede a P1, y no requiere una sintaxis específica de GNU para escribir simplemente.


¡Excelente! Mucho mejor que el mío.
muru

1
@muru: a menudo es más fácil evitar contorsiones si intentas apuntar a la impresión automática; deja que el ciclo funcione para ti. Ese es el hábito en el que he caído de todos modos. Creo que probablemente se describa mejor como un método de poda versus un método de selección : tiendo a terminar negando un patrón en lugar de buscarlo.
mikeserv

Esto se bloqueará cuando procese un archivo de gran tamaño.
Brain90

@ Brain90 - no debería. si puede reproducir su reclamo de manera confiable, debe dirigirse al responsable del mantenimiento de su sed... eso es un error en el que sedestá ejecutando, y no en el script anterior.
mikeserv

1
@mikeserv No lo habría dicho si no fuera así. Su preocupación sobre si me importan o no un par de caracteres es extraña: observé que la expresión sed funcionaba con y sin /P2/qmi sistema; Eso es. Tenía curiosidad por algo y quería compartir lo que encontré.
Alexej Magura

8

con awk

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

8

En sed:

sed -n '/P1/,/P2/p; /P2/q'
  • -nsuprime la impresión predeterminada e imprime líneas entre los rangos de direcciones coincidentes con el pcomando
  • Normalmente, esto coincidiría con ambas secciones, por lo que se cierra ( q) cuando P2coinciden las primeras .

Esto fallará si a P2viene antes P1. Para manejar ese caso, intente:

sed -n '/P1/,/P2/{p; /P2/q}'

1
Estoy en desacuerdo; La respuesta de mikeserv no es mejor que la tuya.
G-Man dice 'Reincorporar a Mónica' el

@ g-man - pshaw. pero solo pensaba lo mismo.
mikeserv

1
@gman - no. Ahora lo entiendo. minas mucho mejor. no {stack}!
mikeserv

1

Si desea omitir los patrones, esta es la awkversión:

awk '/P2/ {exit} /P1/ {f=1; next} f' file

Funciona para mi. ¿Podría agregar más información sobre cómo funciona el comando?
0xAffe

1

Una simple awksolución (una especie de mitad de camino entre la respuesta de Iruvar y  la respuesta de Muru , pero no el uso de una variable):

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

y, como señaló muru, si el primer P2 aparece antes del primer P1, esto no imprimirá nada.

Por supuesto, si desea imprimir todos los rangos P1-P2:

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

solo deja de lado la exitparte:

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

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

Salga inmediatamente después de la impresión, no antes.


0

Para omitir los patrones en sí mismos y mostrar solo el primer bloque coincidente en un solo GNU sed:

sed -nre '/STARTPATTERN/ {:a;n;/ENDPATTERN/{b;};p;ba}' file
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.