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
find
ejecutar comandos en archivos usando-exec
. Conbash -c
, estamos generando unbash
shell que recorre los archivos encontradosfind
y se ejecutatac .. | grep -m1 fileprefix
en cada uno-d" "
con corte.find
comando puede filtrar por el prefijo del archivo; elgrep
no 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
tac
al imprimir el archivo en orden inverso (última línea primero) y luegogrep -m1
para 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
-H
a cadagrep
invocación. O, sigrep
no lo admite, dígale que también busque/dev/null
. Eso no cambiará la salida, pero comogrep
se 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 file
herramienta ~ 7 segundos ytac file | grep -m1 pattern
tomó0.009
.... funcionará si tiene GNU
sed
que admite la-s
opción de archivos separados y un POSIXfind
.Probablemente debería agregar los
! -type d
o-type f
calificadores, 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:
sed
sobrescribe suh
antiguo espacio con una copia de cualquier línea de entrada que coincidasearchstring
, luegod
elige de la salida todas las líneas de entrada, pero la última para cada archivo de entrada. Cuando llega a la última línea,x
cambia sus espacios de retención y de patrón, por lo que sisearchstring
se 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/./!d
a la cola de lased
secuencia de comandos si eso no es deseable) .Esto hará una sola
sed
invocación por cada 65k archivos de entrada, o sea cual sea suARG_MAX
lí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 elF
comando, o bien puede imprimirlosfind
en una lista separada por lote agregando el-print
primario 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
grep
las opciones-H
y-n
opciones 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