¿Cómo leer ciertas líneas después de encontrar un texto?

12

¿Cómo puedo leer un cierto número de líneas después de encontrar algún texto?

P.ej.:

Lea las siguientes 2 líneas después de encontrar "Unix" en:

Test 1
Test 2
Test 3
Test 4
UNIX
Test 5
Test 6
Test 7
Test 8
Test 9

El resultado puede ser:

Test 5
Test 6

Nota: El "Unix" en el último ejemplo es un argumento y, por lo tanto, puede ser cualquier otro texto.

Lo que tengo:

Todavía estoy sin ideas, solo necesito una luz. Pensando en crear otro script para hacer eso.

Frío
fuente

Respuestas:

10

Una awksolución:

$ awk '$0 == "UNIX" {i=1;next};i && i++ <= 2' file
Test 5
Test 6

Explicación

  • /^UNIX$/{i=1;next}: si vemos UNIX, configuramos variable i = 1, procesando a la siguiente entrada.

  • Si ise establece la variable (lo que significa que vimos UNIX), i && i++ <= 2solo se evalúa al valor verdadero en las siguientes dos líneas después UNIX, lo que provoca la awkacción predeterminada realizada print $0.

  • Antes de verlo UNIX, ino estaba definido y comenzaba en la 3ra línea después UNIX, itenía un valor mayor que 2, lo que hacía que la expresión se i && i++ <= 2evaluara como falsa, sin awkhacer nada.

Cuonglm
fuente
Después de probar su solución, recibo este mensaje de error: sintaxis de error cerca de la línea 1 rescatando cerca de la línea 1
Cold
@Cold: ¿Qué corriste? Tenga en cuenta que el $signo al comienzo de mi respuesta es el símbolo del sistema, no parte del awkcomando.
Cuonglm
Otra variante:awk '/^UNIX$/ {s=NR;next} s && NR<=s+2'
musiphil
Sé que @cuonglm
Cold
@Cold: ¿Cuál es su sistema operativo?
Cuonglm
12

Una grepsolución:

grep -A2 -P '^UNIX$' file

Explicación: -A significa: imprimir las dos líneas siguientes después del partido

O awk:

awk '$0=="UNIX"{getline; print; getline; print}' file

Explicación: Esa declaración busca UNIX en la línea ( $0=="UNIX"). Si se da eso, obtiene el siguiente siguiente en su búfer ( getline) e imprime el búfer ( print). Esto se hace dos veces.

O use sed:

sed -n '/^UNIX$/{n;p;n;p}' file

Explicación: Eso sella para UNIX ( /^UNIX$/). Si se encuentra esto, ejecuta la parte en el {...}. nsignifica siguiente, psignifica imprimir. Esto se hace dos veces también.

caos
fuente
Gracias @chaos, probaré las últimas 2 opciones que me des. Por favor, agregue alguna explicación de cada opción, no voy a completar y hacer.
Frío
Si el número de líneas cambia, ¿cuántos cambios haré en las últimas dos opciones? Gracias
Cold
@Cold ver mi edición. Para cambiar el número si las líneas repiten la getline; print;parte en el awkenunciado o la n;p;parte en el sedenunciado.
caos
Gracias @chaos, pero cuanto mayor es el número de líneas, mayor expresión y el cambio no es factible en mi opinión. ¿No piensas? Si 100 líneas?
Frío
@Cold Entonces usaría la solución grep con grep -A100 -P '^UNIX$' file | tail -n +2. La parte de la cola es eliminar el primer gravamen. En los otros (sed, awk) tendrías que escribir bucles, lo que lo hace menos simple.
caos
4
grep -A 2 UNIX file.txt

La página de manual de grep describe la opción así:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.
Centelleos
fuente
Hola @Twinkles, buena respuesta, pero mi grep solo tiene estas opciones "hblcnsviw". Pero la lógica es buena. gracias
Cold
Esto también se imprimirá UNIXen la salida.
Cuonglm
Para omitir el UNIX, tubería a tail: [...] | tail -n +1o a sed: [...] | sed '1d'.
DopeGhoti
1
@DopeGhoti: sus sugerencias taily sed '1d'funcionan correctamente solo si UNIXaparece una sola vez en el texto de entrada. Todas las otras respuestas permiten múltiples ocurrencias. Podría ser mejor sugerir ... | grep -v UNIX. Es cierto que esto se vuelve desordenado si UNIXaparece en las líneas 15 y 17.
G-Man dice 'Restablecer a Monica' el
Buenos puntos. Estoy bastante seguro de que podría hacerse sedcon alguna forma de sed '/UNIX/d;n;n;p/' /path/to/file, que acabo de descubrir y envié como respuesta.
DopeGhoti
0

Esto parece hacer el truco muy bien:

sed -n '/UNIX/{n;p;n;p}' /path/to/file

Prueba de concepto:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6
DopeGhoti
fuente
1
La subshell alrededor de tu forciclo no es necesaria.
Pausado hasta nuevo aviso.
De hecho no lo es; era un remanente de algún otro faffery que estaba en medio de ese caparazón al principio del día. Parens eliminado.
DopeGhoti
0

Puedes usar ex:

ex -s +'1,/UNIX/d|%p|q!' file_or_/dev/stdin

dónde:

kenorb
fuente