Busque una cadena e imprima todo antes y después dentro de un rango

9

Tengo este archivo:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

Quiero buscar en este archivo una cadena específica e imprimir todo antes de esta cadena hasta la apertura {y todo después de esta cadena hasta el cierre }. Traté de lograr esto con sed, pero si trato de imprimir todo en el rango, /{/,/string2/por ejemplo, sed imprime esto:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

Si busco la cadena "string2", necesito que la salida sea:

sometext2{
string2
string3
}

Gracias.

rodrigo
fuente
Bueno, ahora descubrí que necesito los números de línea de la salida en el archivo original para eliminarlos más tarde. Intenté cambiar el comando que @mikeserv proporcionó sin suerte, estoy un poco confundido con la función de retención de sed.
rodrigo
bueno, caramba, rodrigo, no le dijiste eso a nadie más que a ti mismo. se puede hacer, pero es mejor hacerlo así grep -n '' <infile | sed .... Los sedcomandos deberán modificarse; específicamente los bits de /dirección /que buscan ^anclajes de primera línea. Por lo tanto, si estuviera usando mi respuesta que probablemente se podría hacer: grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'. Todas las líneas de salida tendrán como prefijo los números de línea del archivo original seguidos de dos puntos, 1:sometext1{\n2:string1etc. sedfiltrará solo lo que filtraría antes, excepto que cada línea de salida se abre con un número.
mikeserv

Respuestas:

9

Aquí hay dos comandos. Si desea un comando que recorta hasta la última .*{$línea de una secuencia (como lo hace @don_crissti ed) , puede hacer lo siguiente:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

... que funciona agregando cada línea al Hespacio antiguo siguiendo un \ncarácter de línea de línea , sobrescribiendo el hespacio antiguo para cada línea que coincida {$e intercambiando los hespacios antiguos y de patrón para cada línea que coincida ^}, y así vaciar su búfer.

Sólo se imprime líneas que coincidan con una {continuación de una \newline y luego PATTERNen algún momento - y que sólo llega a suceder inmediatamente después de un intercambio de tampón.

Elimina cualquier línea de una serie de {$coincidencias hasta la última de la secuencia, pero puede obtener todas esas inclusivas como:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

Lo que hace es intercambiar el patrón y los hespacios antiguos para cada ...{$.*^}.*secuencia, agrega todas las líneas dentro de la secuencia al Hespacio anterior siguiendo un \ncarácter de línea ey Delige el primer \ncarácter de línea ew en el espacio de patrón para cada ciclo de línea antes de comenzar de nuevo con lo que queda.

Por supuesto, la única vez que obtiene \newline en el espacio del patrón es cuando una línea de entrada coincide ^}, el final de su rango, y cuando vuelve a ejecutar el script en cualquier otra ocasión, simplemente tira de la siguiente línea de entrada de forma habitual.

Sin embargo, cuando PATTERNse encuentra en el mismo espacio de patrón que un \newline, imprime el lote antes de sobrescribirlo ^}nuevamente (para que pueda finalizar el rango y vaciar el búfer) .

Dado este archivo de entrada (gracias don) :

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

Las primeras impresiones:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

...y el segundo...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
mikeserv
fuente
@don_crissti - No lo sé. Es solamente delimita la secuencia de inicio línea con }. Esto podría ser beneficioso para ... open{\nsub;\n{ command; }\n}; close- pero no estoy seguro de que eso sea lo que está sucediendo aquí ...
mikeserv
Hola @mikeserv: tengo una pregunta similar que se plantea aquí unix.stackexchange.com/questions/232509/… , tu solución funciona en un archivo pequeño, pero tengo un archivo grande y me aparece "Espacio de espera desbordado". mensaje de error. ¿Tienes alguna posibilidad, cómo podría resolver esto? Muchas gracias
Narayan Akhade
@NarayanAkhade - no. no sin una revisión, de todos modos. a menos que ... ¿hay grandes extensiones de entrada que no están contenidas con {...}bloques? Si ese es el caso y está usando la primera solución, puede hacerlo /{$/,/^}/Hal comienzo en lugar de solo H. Pero si también probaste la segunda solución y aún encontraste el mismo error, no es probable que te ayude porque esa ya lo hace. Y tampoco descartes ed. don tiene una muy buena respuesta aquí, y también edse puede aplicar para usar archivos temporales de búfer de manera muy simple, lo que debería evitar el desbordamiento del búfer de memoria.
mikeserv
6

Aquí hay una solución con ed:

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

es decir:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

Esto supone que solo hay una línea PATTERNentre cada par, de lo { }contrario obtendrá una salida duplicada para cada línea adicional PATTERNdentro del mismo bloque.
Funcionará para múltiples que { }contengan una sola línea coincidente, PATTERNpor ejemplo, para un archivo de prueba con PATTERNdos secciones diferentes:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

corriendo

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

salidas:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
don_crissti
fuente
¡Tomé mucho de esto, en realidad! ¡Muchas gracias!
mikeserv
Ni siquiera sé que este comando existe. Gracias
rodrigo
4

Con pcregrep:

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

O con GNU grepsiempre que la entrada no contenga bytes NUL:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'
Stéphane Chazelas
fuente
0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

dónde:

  • string4 -> cadena para que coincida
  • t1.txt -> contiene el contenido del archivo mencionado en la consulta
usuario5337995
fuente
-2

sed -n '/ string / p' nombre de archivo

el -n cuando se agrega al comportamiento predeterminado de sed suprimido sed, esta declaración podría no darle exactamente lo que desea, pero debería desplazar la cadena

usuario2995836
fuente