Tengo un archivo como el siguiente y me gustaría imprimir las líneas entre dos patrones de PAT1 y PAT2.

1
2
PAT1
3    - first block
4
PAT2
5
6
PAT1
7    - second block
PAT2
8
9
PAT1
10    - third block

He leído Cómo seleccionar las líneas entre dos marcador de patrones que puede ocurrir varias veces con awk/sed pero tengo curiosidad para ver todas las posibles combinaciones de este, incluyendo o excluyendo el patrón.

¿Cómo puedo imprimir todas las líneas entre dos patrones?

InformationsquelleAutor fedorqui | 2016-08-16

7 Comentarios

  1. 62

    Imprimir líneas entre PAT1 y PAT2

    $ awk '/PAT1/,/PAT2/' file
    PAT1
    3    - first block
    4
    PAT2
    PAT1
    7    - second block
    PAT2
    PAT1
    10    - third block

    O, utilizando las variables:

    awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}' file

    ¿Cómo funciona esto?

    • /PAT1/ coincide con las líneas de tener este texto, así como /PAT2/ hace.
    • /PAT1/{flag=1} establece el flag cuando el texto PAT1 se encuentra en una línea.
    • /PAT2/{flag=0} desactiva el flag cuando el texto PAT2 se encuentra en una línea.
    • flag es un patrón con la acción por defecto, que es print $0: si flag es igual a 1 se imprime la línea. De esta manera, se imprimirá todas esas líneas que se producen desde el momento en que PAT1 se produce y hasta la próxima PAT2 es visto. Esto también imprimir las líneas desde el último partido de PAT1 hasta el final del archivo.

    Imprimir líneas entre PAT1 y PAT2 – no incluyendo PAT1 y PAT2

    $ awk '/PAT1/{flag=1; next} /PAT2/{flag=0} flag' file
    3    - first block
    4
    7    - second block
    10    - third block

    Este utiliza next a pasar la línea que contiene PAT1 con el fin de evitar este impreso.

    Esta llamada a next puede ser disminuido por la redistribución de los bloques: awk '/PAT2/{flag=0} flag; /PAT1/{flag=1}' file.

    Imprimir líneas entre PAT1 y PAT2 – incluyendo PAT1

    $ awk '/PAT1/{flag=1} /PAT2/{flag=0} flag' file
    PAT1
    3    - first block
    4
    PAT1
    7    - second block
    PAT1
    10    - third block

    Mediante la colocación de flag al final, se desencadena la acción que se establece en PAT1 o PAT2: para imprimir en PAT1, no para imprimir en PAT2.

    Imprimir líneas entre PAT1 y PAT2 – incluyendo PAT2

    $ awk 'flag; /PAT1/{flag=1} /PAT2/{flag=0}' file
    3    - first block
    4
    PAT2
    7    - second block
    PAT2
    10    - third block

    Mediante la colocación de flag al principio, se desencadena la acción que se establece previamente y, por tanto, imprimir el patrón de cierre, pero no la partida.

    Imprimir líneas entre PAT1 y PAT2 – excluyendo las líneas de la última PAT1 para el final del archivo si no hay otros PAT2 se produce

    Esto se basa en un solución Ed Morton.

    awk 'flag{
            if (/PAT2/)
               {printf "%s", buf; flag=0; buf=""}
            else
                buf = buf $0 ORS
         }
         /PAT1/{flag=1}' file

    Como un one-liner:

    $ awk 'flag{ if (/PAT2/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /PAT1/{flag=1}' file
    3    - first block
    4
    7    - second block
    
    # note the lack of third block, since no other PAT2 happens after it

    Esto mantiene todas las líneas seleccionadas en un búfer que rellena desde el momento en que PAT1 se encuentra. Entonces, sigue siendo llenado con las siguientes líneas hasta PAT2 se encuentra. En ese punto, se imprime el contenido almacenado y se vacía el búfer.

    • Buena colección de awk comandos para cubrir todos los 4 casos ++
    • Una utilidad de código, he empacado y carga como #gorrión script para hacer posible la reutilización por parte de otros – sparrowhub.org/info/awk-select-lines
  2. 28

    Lo que el clásico sed solución?

    Imprimir líneas entre PAT1 y PAT2 – incluir PAT1 y PAT2

    sed -n '/PAT1/,/PAT2/p' FILE

    Imprimir líneas entre PAT1 y PAT2 – excluir PAT1 y PAT2

    GNU sed

    sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' FILE

    Cualquier sed1

    sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p;};}' FILE

    o incluso (Gracias Sundeep):

    GNU sed

    sed -n '/PAT1/,/PAT2/{//!p}' FILE

    Cualquier sed

    sed -n '/PAT1/,/PAT2/{//!p;}' FILE

    Imprimir líneas entre PAT1 y PAT2 – incluir PAT1 pero no PAT2

    El siguiente incluye sólo el rango de inicio:

    GNU sed

    sed -n '/PAT1/,/PAT2/{/PAT2/!p}' FILE

    Cualquier sed

    sed -n '/PAT1/,/PAT2/{/PAT2/!p;}' FILE

    Imprimir líneas entre PAT1 y PAT2 – incluir PAT2 pero no PAT1

    El siguiente incluye sólo el rango final:

    GNU sed

    sed -n '/PAT1/,/PAT2/{/PAT1/!p}' FILE

    Cualquier sed

    sed -n '/PAT1/,/PAT2/{/PAT1/!p;}' FILE

    1 Nota sobre BSD, Mac OS X, sed

    Un comando como este aquí:

    sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' FILE

    Que emiten un error:

    ▶ sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' FILE
    sed: 1: "/PAT1/,/PAT2/{/PAT1/!{/...": extra characters at the end of p command

    Por esta razón, esta respuesta ha sido editada para incluir BSD y GNU versiones de la uno-trazadores de líneas.

    • Hey, el clásico es incluso más corto!
    • Lo que sobre el caso de la línea de salida también la concordancia con el final del patrón (pero no viceversa)? Que iba a romper su 3er caso al menos.
    • A continuación, el inicio y el final del patrón no está bien elegido o la expresión regular que necesita para ser más precisos.
    • no estoy seguro acerca de otras versiones, pero con GNU sed, la primera puede ser simplificado a sed -n '/PAT1/,/PAT2/{//!p}' file … de manual empty regular expression ‘//’ repeats the last regular expression match
    • Eso es por la sugerencia. POSIX dice: If an RE is empty (that is, no pattern is specified) sed shall behave as if the last RE used in the last command applied (either as an address or as part of a substitute command) was specified. se Ve como la única pregunta que queda aquí es cómo interpretar the last RE. BSD está diciendo algo a esto. Mira aquí (Punto 23): github.com/freebsd/freebsd/blob/master/usr.bin/sed/POSIX
    • gracias por la info adicional… lo que si he entendido correctamente, /PAT1/,/PAT2/{//!p} sólo funcionará si la última RE es dinámico.. si era estático, // se resuelve a /PAT2/
    • Se parece. Difícil encontrar una versión incompatible de probar que. 🙂
    • Nota: no hay una nueva respuesta lo que sugiere mejoras a esta.
    • no es mi mejor ir en él.
    • Creo que es un gran ejemplo de bondad lo que hicimos aquí, por compartir su conocimiento para mejorar otras respuestas. En última instancia, este era mi objetivo cuando me envió esta pregunta, así que podría tener un canónica (otro 😛), un conjunto de fuentes. Muchas gracias!
    • Permítanme compartir con ustedes mi punto de vista sobre esto: una vez me respondió, ¿Cómo seleccionar las líneas entre dos marcador de patrones que puede ocurrir varias veces… y mantuvo conseguir un buen montón de comentarios pidiendo para casos similares. También, cuando se activa en estas etiquetas sentí que yo era la reutilización de los mismos chistes una y otra vez. Por esto pensé que una pregunta-respuesta que cubre la mayoría de los casos podría ser útil. +25 estrellas, +30 votos, ~30K visitas, muchos de los duplicados a esto parecen estar de acuerdo con esto. Por supuesto que no es exhaustivo, pero parece estar funcionando bien.

  3. 4

    Utilizando grep con PCRE (donde esté disponible) para imprimir los marcadores y las líneas entre los marcadores:

    $ grep -Pzo "(?s)(PAT1(.*?)(PAT2|\Z))" file
    PAT1
    3    - first block
    4
    PAT2
    PAT1
    7    - second block
    PAT2
    PAT1
    10    - third block
    • -P perl-regexp, PCRE. No en todos los grep variantes
    • -z Tratar la entrada como un conjunto de líneas, cada una de las
      terminada por un byte cero en lugar de un salto de línea
    • -o imprimir sólo la coincidencia de
    • (?s) DotAll, es decir. dot encuentra saltos de línea, así
    • (.*?) nongreedy encontrar
    • \Z Partido sólo al final de la cadena, o antes de nueva línea al final

    Imprimir líneas entre los marcadores excluyendo marcador final:

    $ grep -Pzo "(?s)(PAT1(.*?)(?=(\nPAT2|\Z)))" file
    PAT1
    3    - first block
    4
    PAT1
    7    - second block
    PAT1
    10    - third block
    • (.*?)(?=(\nPAT2|\Z)) nongreedy encontrar con lookahead para \nPAT2 y \Z

    Imprimir líneas entre los marcadores excluyendo los marcadores:

    $ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(?=(\nPAT2|\Z)))" file
    3    - first block
    4
    7    - second block
    10    - third block
    • (?<=PAT1\n) positivo lookbehind para PAT1\n

    Imprimir líneas entre los marcadores excluyendo el marcador de inicio:

    $ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(PAT2|\Z))" file
    3    - first block
    4
    PAT2
    7    - second block
    PAT2
    10    - third block
  4. 4

    Aquí es otro enfoque

    Incluir ambos patrones (por defecto)

    $ awk '/PAT1/,/PAT2/' file
    PAT1
    3    - first block
    4
    PAT2
    PAT1
    7    - second block
    PAT2
    PAT1
    10    - third block

    Máscara de ambos patrones

    $ awk '/PAT1/,/PAT2/{if(/PAT2|PAT1/) next; print}' file
    3    - first block
    4
    7    - second block
    10    - third block

    Máscara patrón de inicio

    $ awk '/PAT1/,/PAT2/{if(/PAT1/) next; print}' file
    3    - first block
    4
    PAT2
    7    - second block
    PAT2
    10    - third block

    Máscara final patrón

    $ awk '/PAT1/,/PAT2/{if(/PAT2/) next; print}' file
    PAT1
    3    - first block
    4
    PAT1
    7    - second block
    PAT1
    10    - third block
  5. 1

    Usted puede hacer lo que quiera con sed por la supresión de la normal de impresión de patrón de espacio con -n. Por ejemplo, para incluyen los patrones en el resultado que usted puede hacer:

    $ sed -n '/PAT1/,/PAT2/p' filename
    PAT1
    3    - first block
    4
    PAT2
    PAT1
    7    - second block
    PAT2
    PAT1
    10    - third block

    A excluir los patrones y acaba de imprimir lo que hay entre ellas:

    $ sed -n '/PAT1/,/PAT2/{/PAT1/{n};/PAT2/{d};p}' filename
    3    - first block
    4
    7    - second block
    10    - third block

    Que se descompone como

    • sed -n '/PAT1/,/PAT2/ – localizar el intervalo entre PAT1 y PAT2 y suprimir la impresión;

    • /PAT1/{n}; – si coincide con PAT1 mover a n (siguiente) línea;

    • /PAT2/{d}; – si coincide con PAT2 borrar línea;

    • p – imprimir todas las líneas que caen dentro de /PAT1/,/PAT2/ y no fueron omitidos o eliminado.

    • Gracias por el interesante uno-trazadores de líneas y su desglose! Tengo que admitir que todavía prefieren awk, se ve más claro para mí 🙂
    • Me termine de ordenar a través de éste, sólo para encontrar que hek2mgl había un camino más corto — echar un vistazo a su classic sed solución.
  6. 1

    Alternativamente:

    sed '/START/,/END/!d;//d'

    Esto borra todas las líneas, excepto para aquellos entre e incluyendo el INICIO y el FINAL, entonces la //d elimina el INICIO y el FINAL de las líneas desde // causas sed para el uso de los patrones previos.

  7. 1

    Para la integridad, aquí es un Perl solución:

    Imprimir líneas entre PAT1 y PAT2 – incluir PAT1 y PAT2

    perl -ne '/PAT1/../PAT2/and print' FILE

    o:

    perl -ne 'print if /PAT1/../PAT2/' FILE

    Imprimir líneas entre PAT1 y PAT2 – excluir PAT1 y PAT2

    perl -ne '/PAT1/../PAT2/and !/PAT1/and !/PAT2/and print' FILE

    o:

    perl -ne 'if (/PAT1/../PAT2/) {print unless /PAT1/or /PAT2/}' FILE 

    Imprimir líneas entre PAT1 y PAT2 – excluir PAT1 sólo

    perl -ne '/PAT1/../PAT2/and !/PAT1/and print' FILE

    Imprimir líneas entre PAT1 y PAT2 – excluir PAT2 sólo

    perl -ne '/PAT1/../PAT2/and !/PAT2/and print' FILE

    Ver también:

    • Operador de rango sección en perldoc perlop para más información sobre el /PAT1/../PAT2/ gramática:

    Operador de rango

    …En escalar contexto, «..» devuelve un valor booleano. El operador es
    biestable, como un flip-flop, y emula a la línea de rango (coma)
    operador de sed, awk, y varios editores.

    • Para la -n opción, consulte perldoc perlrun, lo que hace que Perl se comportan como sed -n.

    • Perl Libro De Cocina, 6.8 para una discusión detallada de la extracción de un intervalo de líneas.

Dejar respuesta

Please enter your comment!
Please enter your name here