Necesito buscar múltiples archivos de registro (todos los archivos generados en las últimas 24 horas, todos guardados en el mismo directorio) para encontrar la última aparición de una cadena. Este es el comando que escribí:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
Pero esto solo devuelve la última línea para un archivo. ¿Alguna sugerencia sobre cómo ajustar esto para obtener todas las líneas?
bash
shell-script
text-processing
grep
Lokesh
fuente
fuente

Respuestas:
Asumiendo instalaciones GNU:
fuente
findejecutar comandos en archivos usando-exec. Conbash -c, estamos generando unbashshell que recorre los archivos encontradosfindy se ejecutatac .. | grep -m1 fileprefixen cada uno-d" "con corte.findcomando puede filtrar por el prefijo del archivo; elgrepno debe ser necesario para eso. También es sorprendente que la cadena de búsqueda no figure en esta respuesta.Si todo está en un solo directorio, puede hacer:
Si se trata de archivos grandes, podría valer la pena acelerar el proceso
tacal imprimir el archivo en orden inverso (última línea primero) y luegogrep -m1para que coincida con la primera aparición. De esa manera, evita tener que leer todo el archivo:Ambos asumen que no hay directorios que coincidan
fileprefix. Si lo hay, obtendrá un error que puede ignorar. Si eso es un problema, busca solo archivos:Si también necesita imprimir el nombre del archivo, agréguelo
-Ha cadagrepinvocación. O, sigrepno lo admite, dígale que también busque/dev/null. Eso no cambiará la salida, pero comogrepse le dan múltiples archivos, siempre imprimirá el nombre del archivo para cada hit:fuente
tac. Saldrá tan pronto como se encuentre el primer partido. Acabo de probar con un archivo de texto 832M y un patrón encontrado en la última línea.grep -m 1 pattern fileherramienta ~ 7 segundos ytac file | grep -m1 patterntomó0.009.... funcionará si tiene GNU
sedque admite la-sopción de archivos separados y un POSIXfind.Probablemente debería agregar los
! -type do-type fcalificadores, sin embargo, porque tratar de leer un directorio No será muy útil, y estrechando aún más la gama de archivos normales podría evitar un colgante de lectura en una tubería o un archivo de dispositivo serie.La lógica es increíblemente simple:
sedsobrescribe suhantiguo espacio con una copia de cualquier línea de entrada que coincidasearchstring, luegodelige de la salida todas las líneas de entrada, pero la última para cada archivo de entrada. Cuando llega a la última línea,xcambia sus espacios de retención y de patrón, por lo que sisearchstringse encuentra en absoluto mientras lee el archivo, la última aparición de este tipo se imprimirá automáticamente en la salida, de lo contrario, escribirá una línea en blanco. (agregue/./!da la cola de lasedsecuencia de comandos si eso no es deseable) .Esto hará una sola
sedinvocación por cada 65k archivos de entrada, o sea cual sea suARG_MAXlímite. Esta debería ser una solución muy eficaz, y se implementa de manera bastante simple.Si también desea los nombres de archivo, dado un GNU reciente
sed, puede escribirlos en líneas separadas con elFcomando, o bien puede imprimirlosfinden una lista separada por lote agregando el-printprimario después+.fuente
Qué tal si:
Lo anterior le brinda una buena salida con la última aparición de una cadena de búsqueda en cada archivo seguido del nombre del archivo respectivo después de la coma (modifique la parte ", $ 1" bajo echo para cambiar el formato o eliminarlo si no es necesario). El resultado de muestra que busca la cadena de búsqueda '10' en archivos con un prefijo de nombre "archivo" es el siguiente:
fuente
Utiliza
greplas opciones-Hy-nopciones de GNU para imprimir siempre el nombre de archivo y el número de lino de todas las coincidencias, luego lo ordena por nombre de archivo y número de lino, y lo canaliza a awk, que almacena la última coincidencia para cada nombre de archivo en una matriz, y finalmente imprime eso.Un método bastante de fuerza bruta, pero funciona.
fuente