Haga coincidir el patrón A e imprímalo solo cuando el patrón B coincida, incluida la siguiente línea

Haga coincidir el patrón A e imprímalo solo cuando el patrón B coincida, incluida la siguiente línea

Estoy buscando obtener todas las líneas que tienen la palabra 'cadena_búsqueda' + la línea después + la línea que coincide con 'mod' antes.
Lo intenté:

grep -n 'mod\|search_string' ip | grep --before 1 search_string> inter  
grep -n --after 1 search_string ip >> inter  
sort -t':' -k1,1n -u inter -o op

¿Existe una mejor manera?

Archivo:

mod start1  
some lines  
mod start2  
other lines  
mod start3  
 many other lines  
 search_string yada yada  
 hello  
 many other lines  
 search_string yada yada  
 bye  
mod start4  
 search_string baba baba  
 this too  
mod start5  

Rendimiento esperado :

mod start3  
 search_string yada yada   
 hello  
 search_string yada yada  
 bye  
mod start4  
 search_string baba baba  
 this too

Respuesta1

awk '
   $0 ~ /mod/ { md=$0 }
   $0 ~ /search_string/ { if(md!="") { print md }; md="" ; print; getline; print }
   '

Explicación:

  • Una línea que contiene modse guarda como md.
  • Una línea que contiene search_stringactivadores que imprimen lo guardado previamente md, la línea en sí y la línea siguiente.
  • if(md!="")y md=""están ahí para asegurarse de que no obtenga modlíneas duplicadas cuando haya muchas search_string-s debajo de una sola mod( mod start3en su ejemplo).

Nota:

  • Una línea que contenga ambos mody search_stringromperá esta lógica.

Respuesta2

Su archivo contiene caracteres de "retorno de carro". Es mejor eliminarlos en Unix. Para imprimir lo que imprime la secuencia de comandos que publicó (sin retornos de carro), intente:

awk '{gsub(/\r/,"")}
     /mod/          { a = $0 }
     /search_string/{ if(a!=""){print(a);a=""}
                      print;getline;print
                    }
    ' infile

O como una sola línea:

$ awk '{gsub(/\r/,"")}/mod/{a=$0}/search_string/{if(a!=""){print(a);a=""}print;getline;print}' infile

mod start3  
 search_string yada yada  
 hello  
 search_string yada yada  
 bye  
mod start4  
 search_string baba baba  
 this too  

Como es posible utilizar un separador de registros de varios caracteres en (GNU) awk, podemos configurar el separador de registros mode imprimir solo los registros que contengan search_string. Se requiere printf para reconstruir el registro original.

Para imprimir lo que publicó como "Resultado esperado", intente:

awk '/search_string/{printf("mod%s", $0)}' RS=mod infile

Respuesta3

Si quieres esto en un script de Python:

# Read file into memory.
with open('myfile.txt') as f:
    lines = [line.rstrip() for line in f]

# Loops through lines backwards, looking for string and optionally mod.
output_lines = list()
find_mod = False
for i, line in enumerate(lines[::-1]):
    if 'search_string' in line:
        output_lines.append(lines[::-1][i-1])
        output_lines.append(lines[::-1][i])
        find_mod = True
    elif find_mod and 'mod' in line:
        output_lines.append(lines[::-1][i])
        find_mod=False

print("\n".join(output_lines[::-1]))

información relacionada