grep -R(a excepción del GNU modificado que se grepencuentra 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 -rcon 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).
grepencuentra 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 grepimplementaciones, 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 grepanterior 2.6, puede usar la --mmapopció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 grep2.6
greppuede descartar los búferes que ha procesado hasta ahora. Puedegrepgenerar la salida de formayesindefinida sin utilizar más de unos pocos kilobytes de memoria. El problema es el tamaño de las líneas.--null-dataopció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á
execun grep para cada archivo.fuente
find -print0 | xargs -0 grep -ne 'expression'find -print0yxargs -0ahora: 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
grepsalidas usan un delimitador que es legal en los nombres de archivo). También necesita cotizar$file.forque 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