GNU/Linux >> Tutoriales Linux >  >> Linux

Imprimir la línea anterior si se cumple la condición

Otra opción:invertir el archivo e imprimir el siguiente línea si la condición coincide:

tac file | awk '$1 == "BB" && $2 > 1 {getline; print}' | tac

Con respecto a la generalidad

Creo que debe mencionarse que la solución más general a esta clase de problema implica dos pasos:

  • la primera pasada para agregar un número de fila decimal ($REC) al frente de cada línea, agrupando efectivamente las líneas en registros por $REC
  • la segunda pasada se activa en la primera instancia de cada nuevo valor de $REC como un límite de registro (restableciendo $CURREC), y luego avanza en el idioma AWK nativo con respecto a los registros que siguen a la coincidencia de $CURREC.

En el archivo intermedio, alguna secuencia de dígitos decimales seguidos de un separador (por razones humanas, generalmente un tabulador o espacio agregado) se analiza (también conocido como corte conceptual) como fuera de banda con respecto al archivo de referencia.

Monstruo de pegado de línea de comandos

Incluso confinado a la línea de comandos, es fácil asegurarse de que el archivo intermedio nunca llegue al disco. Solo necesita usar un shell avanzado como ZSH (mi favorito) que admite la sustitución de procesos:

paste <( <input.txt awk "BEGIN { R=0; N=0; } /Header pattern/ { N=1; } { R=R+N; N=0; print R; }" ) input.txt | awk -f yourscript.awk 

Hagamos que esa frase sea más adecuada para la exposición:

P="/Header pattern/"
X="BEGIN { R=0; N=0; } $P { N=1; } { R=R+N; N=0; print R; }"
paste <( <input.txt awk $X ) input.txt | awk -f yourscript.awk 

Esto inicia tres procesos:el script AWK en línea trivial, paste y el script AWK que realmente quería ejecutar en primer lugar.

Detrás de escena, el <() La construcción de la línea de comando crea una canalización con nombre y pasa el nombre de la canalización para pegarlo como el nombre de su primer archivo de entrada. Para paste segundo archivo de entrada, le damos el nombre de nuestro archivo de entrada original (este archivo se lee secuencialmente, en paralelo, por dos procesos diferentes, que consumirán entre ellos como máximo uno leer desde el disco, si el archivo de entrada está frío).

La tubería mágica con nombre en el medio es un FIFO en memoria que el antiguo Unix probablemente manejaba a unos 16 kB de tamaño promedio (pausando intermitentemente el paste proceso si el yourscript.awk el proceso es lento para drenar este FIFO).

Quizás el Unix moderno arroja un búfer más grande allí porque puede, pero ciertamente no es un recurso escaso que deba preocuparte, hasta que escribas tu primer verdaderamente línea de comando avanzada con redirección de procesos que involucra estos cientos o miles :-)

Consideraciones de rendimiento adicionales

En las CPU modernas, estos tres procesos podrían ejecutarse fácilmente en núcleos separados.

Los primeros dos de estos procesos limitan con lo verdaderamente trivial:un script AWK con una sola coincidencia de patrón y algunas tareas menores de contabilidad, pegado llamado con dos argumentos. yourscript.awk será difícil correr más rápido que estos.

¿Qué, su máquina de desarrollo no tiene núcleos ligeramente cargados para hacer que este patrón maestro de solución shell-maestro sea casi gratuito en el dominio de ejecución?

Anillo, anillo.

¿Hola?

Oye, es para ti. 2018 acaba de llamar y quiere recuperar su problema.

2020 es oficialmente el indulto de MTV:así es como nos gusta, pipas mágicas por nada y núcleos gratis. Sin mencionar en voz alta a ningún proveedor de chips TLA en particular que esté sacudiendo el espacio en estos días.

Como consideración final de rendimiento, si no desea la sobrecarga de analizar los números de registros reales:

X="BEGIN { N=0; } $P { N=1; } { print N; N=0; }"

Ahora su archivo intermedio en FIFO está anotado con solo dos caracteres adicionales antepuestos a cada línea ('0' o '1' y el carácter separador predeterminado agregado por paste ), con '1' marcando la primera línea en el registro.

FIFO con nombre

Bajo el capó, estos no son diferentes a los FIFO mágicos instanciados por Unix cuando escribe cualquier comando de canalización normal:

cat file | proc1 | proc2 | proc2 

Tres conductos sin nombre (y todo un proceso dedicado a cat ni siquiera necesitabas).

Es casi desafortunado que el verdaderamente excepcional la conveniencia de los flujos de entrada estándar/salida estándar predeterminados como preadministrados por el shell oscurece la realidad de que paste $magictemppipe1 $magictemppipe2 no tiene consideraciones de rendimiento adicionales en las que valga la pena pensar, en el 99% de todos los casos.

"Usa el <() Articulación en Y, Luke".

Su reflejo instintivo hacia la descomposición semántica natural en el dominio del problema se beneficiará inmensamente.

Si alguien hubiera tenido el ingenio de nombrar la construcción de shell <() como operador de YODA en primer lugar, sospecho que habría sido presionado para el servicio universal hace al menos una década sólida.


Esta puede ser una forma:

$ awk '$1=="BB" && $2>1 {print f} {f=$1}' file
AAAAAAAAAAAAA

Explicación

  • $1=="BB" && $2>1 {print f} si el primer campo es exactamente BB y el segundo campo es más grande que 1 , luego imprima f , un valor almacenado.
  • {f=$1} almacenar la línea actual en f , para que sea accesible al leer la siguiente línea.

Linux
  1. ¿Imprimir dos archivos en dos columnas?

  2. ¿Imprimir línea anterior después de una coincidencia de patrón usando Sed?

  3. Ejemplos de comandos awk en Linux

  4. awk:comando no encontrado

  5. ver tamaño de archivo en linux

Cómo leer archivos línea por línea en Bash

Cómo leer un archivo línea por línea en Bash

Comando AWK en Linux/Unix

Línea de comentario de Ansible en el archivo

¿Cómo imprimir la última línea de un archivo comprimido gz en la línea de comando?

Imprimir la dirección mac en el archivo