unix - varios - usar grep para buscar archivos
Grep un archivo de registro para la última aparición de una cadena entre dos cadenas (5)
Otra solución que grep sería sed:
tac file | sed -n ''0,/<tag>/(.*/)<//tag>/s///1/p''
tac file
imprime el archivo en el orden inverso ( cat
hacia atrás), luego sed
procede desde la línea de entrada 0
hasta la primera aparición de <tag>.*</tag>
, y sustituye <tag>.*</tag>
con solo el parte que estaba dentro de <tag>
. El indicador p
imprime la salida, que fue suprimida por -n
.
Editar: Esto no funciona si <tag>
y </tag>
están en líneas diferentes. Todavía podemos usar sed
para eso:
tac file | sed -n ''/<//tag>/,$p; /<tag>/q'' | sed ''s/.*<tag>//; s/<//tag>.*//'' | tac
De nuevo usamos tac
para leer el archivo hacia atrás, luego el primer comando sed
lee desde la primera aparición y se cierra cuando lo encuentra. Solo se imprimen las líneas intermedias. Luego lo pasamos a otro proceso sed
para despojarlo y finalmente revertir las líneas nuevamente con tac
.
Tengo un archivo de registro trace.log
. En él, necesito grep para el contenido incluido dentro de las cadenas <tag>
y </tag>
. Hay varios conjuntos de este par de cadenas, y solo necesito devolver el contenido entre el último conjunto (en otras palabras, desde la tail
del archivo de registro).
Crédito adicional: ¿De alguna manera puedo devolver el contenido contenido en las dos cadenas solo si el contenido contiene "testString"?
Gracias por mirar.
EDITAR: Los parámetros de búsqueda y están contenidos en diferentes líneas con alrededor de 100 líneas de contenido que los separan. El contenido es lo que busco ...
Un poco de awk no probado que maneja múltiples líneas:
awk ''
BEGIN {retain="false"}
/</tag>/ {retain = retain + $0; keep="false"; next}
/<tag>/ {keep = "true"; retain = $0; next}
keep == "true" {retain = retain + $0}
END {print retain}
'' filename
Comenzamos simplemente leyendo el archivo; cuando golpeamos el, comenzamos a mantener las líneas. Cuando golpeamos el, nos detenemos. Si golpeamos a otro, borramos la cadena retenida y comenzamos nuevamente. Si quieres todas las cadenas, imprime en cada
Use tac
para imprimir el archivo al revés y luego grep -m1
para simplemente imprimir un resultado. La mirada hacia atrás y hacia adelante verifica el texto entre <tag>
y </tag>
.
tac a | grep -m1 -oP ''(?<=tag>).*(?=</tag>)''
Prueba
Dado este archivo
$ cat a
<tag> and </tag>
aaa <tag> and <b> other things </tag>
adsaad <tag>and last one</tag>
$ tac a | grep -m1 -oP ''(?<=tag>).*(?=</tag>)''
and last one
Actualizar
EDITAR: Los parámetros de búsqueda y están contenidos en diferentes líneas con alrededor de 100 líneas de contenido que los separan. El contenido es lo que busco ...
Entonces es un poco más complicado:
tac file | awk ''/<//tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};
/<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit};
p'' | tac
La idea es invertir el archivo y usar una bandera p
para verificar si la <tag>
ya apareció o no. Comenzará a imprimirse cuando </tag>
aparezca y termine cuando <tag>
venga (porque estamos leyendo al revés).
-
split($0, a, "</tag>"); $0=a[1];
obtiene los datos antes de</tag>
-
split($0, a, "<tag>" ); $0=a[2];
obtiene los datos después de<tag>
Prueba
Dado un archivo como este:
<tag> and </tag>
aaa <tag> and <b> other thing
come here
and here </tag>
some text<tag>tag is starting here
blabla
and ends here</tag>
El resultado será:
$ tac a | awk ''/<//tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p'' | tac
tag is starting here
blabla
and ends here
Si, como yo, no tienes acceso a tac porque tu administrador de sistema no jugará bola, puedes probar:
grep pattern file | tail -1
perl -e ''$/=undef; $f=<>; push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1]'' ex.txt
Crédito adicional: ¿De alguna manera puedo devolver el contenido contenido en las dos cadenas solo si el contenido contiene "testString"?
perl -e ''$/=undef; $f=<>; push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1] if ($a[-1]~=/teststring/);'' ex.txt