Je faisais une search très simple:
grep -R Milledgeville ~/Documents
Et après quelque time cette erreur est apparue:
grep: memory exhausted
Comment puis-je éviter cela?
J'ai 10 Go de RAM sur mon système et quelques applications en cours d'exécution, donc je suis vraiment surpris qu'un grep simple manque de memory. ~/Documents
est d'environ 100 Go et contient toutes sortes de files.
grep -RI
pourrait ne pas avoir ce problème, mais je veux aussi chercher dans des files binarys.
Deux problèmes potentiels:
grep -R
(à l'exception du grep
GNU modifié trouvé sur OS / X 10.8 et plus) suit les liens symboliques, donc même s'il n'y a que 100 Go de files dans ~/Documents
, il peut y avoir un lien symbolique vers /
vers le haut de l'set du système de files, y compris les files comme /dev/zero
. Utilisez grep -r
avec un grep
GNU plus récent ou utilisez la syntaxe standard:
find ~/Documents -type f -exec grep Milledgeville /dev/null {} +
(notez cependant que le statut de sortie ne reflétera pas le fait que le model est apparié ou non).
grep
trouve les lignes qui correspondent au model. Pour cela, il doit charger une ligne à la fois en memory. GNU grep
contrairement à beaucoup d'autres implémentations grep
n'a pas de limite sur la taille des lignes qu'il lit et supporte la search dans les files binarys. Donc, si vous avez un file avec une très grande ligne (c'est-à-dire avec deux caractères de ligne très éloignée), plus grand que la memory disponible, il échouera.
Cela se produit généralement avec un file clairsemé. Vous pouvez le reproduire avec:
truncate -s200G some-file grep foo some-file
Celui-ci est difficile à contourner. Vous pourriez le faire comme (toujours avec GNU grep
):
find ~/Documents -type f -exec sh -c 'for i do tr -s "\0" "\n" < "$i" | grep --label="$i" -He "$0" done' Milledgeville {} +
Cela convertit les séquences de caractères NUL en un caractère de nouvelle ligne avant d'alimenter l'input en grep
. Cela couvrirait les cas où le problème est dû à des files épars.
Vous pouvez l'optimiser en le faisant uniquement pour les files volumineux:
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 les files ne sont pas clairsemés et que vous avez une version de GNU grep
antérieure à 2.6
, vous pouvez utiliser l'option --mmap
. Les lignes seront mmapped dans la memory par opposition à copyr là, ce qui signifie que le système peut toujours récupérer la memory en paginant les pages vers le file. Cette option a été supprimée dans GNU grep
2.6
Je peux penser à quelques façons de contourner ceci:
Au lieu de grepper tous les files à la fois, faites un file à la fois. Exemple:
find /Documents -type f -exec grep -H Milledgeville "{}" \;
Si vous avez seulement besoin de savoir quels files contiennent les mots, faites plutôt grep -l
. Puisque grep s'arrêtera de chercher après le premier hit, il n'aura pas à lire d'énormes files
Si vous voulez également le text, vous pouvez enstringr deux files greps séparés:
for file in $( grep -Rl Milledgeville /Documents ); do grep -H Milledgeville "$file"; done
Je fais habituellement
find ~/Documents | xargs grep -ne 'expression'
J'ai essayé un tas de methods, et trouvé que c'était le plus rapide. Notez que cela ne gère pas très bien les files avec des espaces. Si vous savez que c'est le cas et que vous avez une version GNU de grep, vous pouvez utiliser:
find ~/Documents -print0 | xargs -0 grep -ne 'expression'
Sinon, vous pouvez utiliser:
find ~/Documents -exec grep -ne 'expression' "{}" \;
Ce qui exec
un grep pour chaque file.