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 exactamenteBB
y el segundo campo es más grande que1
, luego imprimaf
, un valor almacenado.{f=$1}
almacenar la línea actual enf
, para que sea accesible al leer la siguiente línea.