grep -R
(a excepción del GNU modificado que se grep
encuentra en OS / X 10.8 y superior) sigue los enlaces simbólicos, por lo que incluso si solo hay 100 GB de archivos ~/Documents
, podría haber un enlace simbólico, /
por ejemplo, y terminará escaneando todo el sistema de archivos, incluidos los archivos como /dev/zero
. Use grep -r
con GNU más nuevo grep
, o use la sintaxis estándar:
find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(sin embargo, tenga en cuenta que el estado de salida no reflejará el hecho de que el patrón coincide o no).
grep
encuentra las líneas que coinciden con el patrón. Para eso, tiene que cargar una línea a la vez en la memoria. GNU grep
, a diferencia de muchas otras grep
implementaciones, no tiene un límite en el tamaño de las líneas que lee y admite la búsqueda en archivos binarios. Entonces, si tiene un archivo con una línea muy grande (es decir, con dos caracteres de nueva línea muy separados), más grande que la memoria disponible, fallará.
Eso normalmente sucedería con un archivo disperso. Puedes reproducirlo con:
truncate -s200G some-file
grep foo some-file
Ese es difícil de evitar. Podrías hacerlo como (todavía con GNU grep
):
find ~/Documents -type f -exec sh -c 'for i do
tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
done' Milledgeville {} +
Eso convierte secuencias de caracteres NUL en un carácter de nueva línea antes de alimentar la entrada grep
. Eso cubriría los casos en que el problema se deba a la escasez de archivos.
Puede optimizarlo haciéndolo solo para archivos grandes:
find ~/Documents -type f \( -size -100M -exec \
grep -He Milledgeville {} + -o -exec sh -c 'for i do
tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0"
done' Milledgeville {} + \)
Si los archivos no son escasos y tiene una versión de GNU grep
anterior 2.6
, puede usar la --mmap
opción. Las líneas se mapearán en la memoria en lugar de copiarse allí, lo que significa que el sistema siempre puede recuperar la memoria paginando las páginas al archivo. Esa opción fue eliminada en GNU grep
2.6
grep
puede descartar los búferes que ha procesado hasta ahora. Puedegrep
generar la salida de formayes
indefinida sin utilizar más de unos pocos kilobytes de memoria. El problema es el tamaño de las líneas.--null-data
opción grep de GNU también puede ser útil aquí. Obliga al uso de NUL en lugar de nueva línea como un terminador de línea de entrada.Yo suelo hacer
Probé varios métodos y descubrí que este es el más rápido. Tenga en cuenta que esto no maneja muy bien los archivos con espacios del nombre del archivo. Si sabe que este es el caso y tiene una versión GNU de grep, puede usar:
Si no, puedes usar:
Lo cual será
exec
un grep para cada archivo.fuente
find -print0 | xargs -0 grep -ne 'expression'
find -print0
yxargs -0
ahora: los tres BSD, MINIX 3, Solaris 11, ...Se me ocurren algunas maneras de evitar esto:
En lugar de agrupar todos los archivos a la vez, haga un archivo a la vez. Ejemplo:
Si solo necesita saber qué archivos contienen las palabras, hágalo
grep -l
. Dado que grep dejará de buscar después del primer golpe, no tendrá que seguir leyendo ningún archivo enormeSi también desea el texto real, puede encadenar dos greps separados:
fuente
grep
salidas usan un delimitador que es legal en los nombres de archivo). También necesita cotizar$file
.for
que el archivo se procese como dos argumentos)Estoy usando un disco de 6TB para buscar datos perdidos, y la memoria se agotó. Esto también debería funcionar para otros archivos.
La solución que se nos ocurrió fue leer el disco en fragmentos utilizando dd y haciendo un grep de los fragmentos. Este es el código (big-grep.sh):
fuente