
Estoy intentando imprimir solo la <N>
enésima línea antes de un patrón de búsqueda. grep -B<N>
imprime todas las <N>
líneas antes del patrón de búsqueda. Vi el código awkaquíque puede imprimir solo la <N>
enésima línea después del patrón de búsqueda.
awk 'c&&!--c;/pattern/{c=N}' file
¿Cómo modificar esto para imprimir solo la <N>
enésima línea antes de cada línea que coincida pattern
? Por ejemplo, aquí está mi archivo de entrada.
...
...
0.50007496 0.42473932 0.01527831
0.99997456 0.97033575 0.44364198
Direct configuration= 1
0.16929051 0.16544726 0.16608723
0.16984300 0.16855274 0.50171112
...
...
0.50089841 0.42608090 0.01499159
0.99982054 0.97154975 0.44403547
Direct configuration= 2
0.16931296 0.16553376 0.16600890
0.16999941 0.16847055 0.50170694
...
Necesito un comando que pueda devolverme el 2nd line
valor anterior a la cadena de búsqueda Direct configuration
. Estoy intentando ejecutar estoSUSE-Linux
Respuesta1
Es necesario utilizar un buffer de líneas.
Prueba esto:
awk -v N=4 -v pattern="example.*pattern" '{i=(1+(i%N));if (buffer[i]&& $0 ~ pattern) print buffer[i]; buffer[i]=$0;}' file
Establezca N
el valor en la enésima línea antes del patrón a imprimir.
Establezca pattern
el valor de la expresión regular para buscar.
buffer
es una serie de N
elementos. Se utiliza para almacenar las líneas. Cada vez que se encuentra el patrón, N
se imprime la enésima línea antes del patrón.
Respuesta2
Ese código no funciona para las líneas anteriores. Para obtener líneas antes del patrón coincidente, debe guardar de alguna manera las líneas ya procesadas. Como awk
solo tiene matrices asociativas, no puedo pensar en una forma igualmente simple de hacer lo que quieres awk
, así que aquí tienes una solución en Perl:
perl -ne 'push @lines,$_; print $lines[0] if /PAT/; shift(@lines) if $.>LIM;' file
Cambie PAT
al patrón que desea combinar y LIM
al número de líneas. Por ejemplo, para imprimir la quinta línea antes de cada aparición de foo
, ejecutaría:
perl -ne 'push @lines,$_; print $lines[0] if /foo/; shift(@lines) if $.>5;' file
Explicación
perl -ne
: lea el archivo de entrada línea por línea y aplique el script proporcionado por-e
a cada línea.push @lines,$_
: agrega la línea actual ($_
) a la matriz@lines
.print $lines[0] if /PAT/
: imprime el primer elemento de la matriz@lines
($lines[0]
) si la línea actual coincide con el patrón deseado.shift(@lines) if $.>LIM;
:$.
es el número de línea actual. Si eso es mayor que el límite, elimine el primer valor de la matriz@lines
. El resultado es que@lines
siempre tendrán las últimasLIM
líneas.
Respuesta3
tac file | awk 'c&&!--c;/pattern/{c=N}' | tac
Pero esto tiene la misma omisión que el caso de uso 'hacia adelante' cuando hay múltiples coincidencias dentro de N líneas entre sí.
Y no funcionará tan bien cuando la entrada se canalice desde un proceso en ejecución, pero es la forma más sencilla cuando el archivo de entrada está completo y no crece.
Respuesta4
Manera alternativa con sed
.
Paranorte=1:
sed '$!N; /.*\n.*pattern/P; D' FILE
Paranorte=2
sed '1N; $!N; /.*\n.*\n.*pattern/P; D' FILE
Para elnorte=2caso, la primera línea leerá la siguienteN-1Las líneas en el espacio del patrón luego comienzan un N;P;D
ciclo: lea otra línea y, si la última línea en el espacio del patrón coincide, imprima la primera línea en el espacio del patrón y luego elimínela, comenzando un nuevo ciclo.
La desventaja es que es necesario modificarlo para diferentes valores denorte:
Paranorte=3:
sed '1{N;N}; $!N; /.*\n.*\n.*\n.*pattern/P; D' FILE
Paranorte=4:
sed '1{N;N;N}; $!N; /.*\n.*\n.*\n.*\n.*pattern/P; D' FILE
por lo que rápidamente se vuelve engorroso, aunque para valores mayores denortepodrías preparar un archivo de script y pasarlo a sed
.