web-dev-qa-db-fra.com

Grep le plus rapide possible

J'aimerais savoir s'il y a un conseil à faire grep aussi vite que possible. J'ai une assez grande base de fichiers texte à rechercher le plus rapidement possible. Je les ai toutes réduites en minuscules pour pouvoir me débarrasser de -i option. Cela rend la recherche beaucoup plus rapide.

En outre, j'ai découvert que -F et -P modes sont plus rapides que le mode par défaut. J'utilise le premier lorsque la chaîne de recherche n'est pas une expression régulière (texte brut), le dernier si regex est impliqué.

Quelqu'un at-il une expérience dans l'accélération de grep? Peut-être le compiler à partir de rien avec un drapeau particulier (je suis sous Linux CentOS), organiser les fichiers d'une certaine manière ou peut-être rendre la recherche parallèle d'une certaine manière?

80
pistacchio

Essayez avec GNU parallel , qui inclut n exemple d'utilisation avec grep :

grep -r _ greps récursivement dans les répertoires. Sur les CPU multicœurs GNU parallel peut souvent accélérer cela.

find . -type f | parallel -k -j150% -n 1000 -m grep -H -n STRING {}

Cela exécutera 1,5 tâche par cœur et donnera 1000 arguments à grep.

Pour les gros fichiers, il peut diviser l’entrée en plusieurs morceaux avec le --pipe et --block arguments:

 parallel --pipe --block 2M grep foo < bigfile

Vous pouvez également l'exécuter sur plusieurs machines différentes via SSH (ssh-agent nécessaire pour éviter les mots de passe):

parallel --pipe --sshlogin server.example.com,server2.example.net grep foo < bigfile
104
Chewie

Si vous recherchez des fichiers très volumineux, il peut être très utile de définir vos paramètres régionaux.

GNU grep va beaucoup plus vite dans les paramètres régionaux C qu'avec UTF-8.

export LC_ALL=C
70
daveb

Ripgrep prétend maintenant être le plus rapide.

https://github.com/BurntSushi/ripgrep

Inclut également le parallélisme par défaut

 -j, --threads ARG
              The number of threads to use.  Defaults to the number of logical CPUs (capped at 6).  [default: 0]

Du README

Il est construit sur le moteur regex de Rust. Le moteur regex de Rust utilise des automates finis, SIMD et des optimisations littérales agressives pour rendre la recherche très rapide.

12
rado

Apparemment, utiliser --mmap peut aider sur certains systèmes:

http://lists.freebsd.org/pipermail/freebsd-current/2010-August/019310.html

5
Sandro Pasquali

Ce n'est pas strictement une amélioration de code, mais quelque chose que j'ai trouvé utile après avoir exécuté grep sur plus de 2 millions de fichiers.

J'ai déplacé l'opération sur un disque SSD bon marché (120 Go). À environ 100 USD, c'est une option abordable si vous traitez régulièrement de nombreux fichiers.

4
the wanderer

Si vous ne vous souciez pas des fichiers contenant la chaîne, vous pouvez séparer lecture et grepping en deux travaux, car il peut être coûteux de générer grep plusieurs fois - une fois pour chaque petit fichier.

  1. Si vous avez un très gros fichier:

    parallel -j100% --pipepart --block 100M -a <very large SEEKABLE file> grep <...>

  2. Beaucoup de petits fichiers compressés (triés par inode)

    ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j80% --group "gzcat {}" | parallel -j50% --pipe --round-robin -u -N1000 grep <..>

Je compresse généralement mes fichiers avec lz4 pour un débit maximal.

  1. Si vous voulez juste le nom du fichier avec la correspondance:

    ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j100% --group "gzcat {} | grep -lq <..> && echo {}

3
Alex V

En me basant sur la réponse de Sandro, j’ai examiné la référence qu’il a fournie ici et j’ai joué avec BSD grep contre GNU grep. Mes résultats rapides ont montré: GNU grep est beaucoup, beaucoup plus rapide.

Donc, ma recommandation à la question initiale "grep le plus rapide possible": Assurez-vous que vous utilisez GNU grep plutôt que BSD grep (qui est la valeur par défaut sous MacOS, par exemple).

2
Chris

Personnellement, j'utilise ag (recherche d'argent) au lieu de grep et c'est beaucoup plus rapide. Vous pouvez également le combiner avec un bloc parallèle et un bloc de tuyaux.

https://github.com/ggreer/the_silver_searcher

Mise à jour: J'utilise maintenant https://github.com/BurntSushi/ripgrep , qui est plus rapide que ag en fonction de votre cas d'utilisation.

2
Jinxmcg

Une chose que j'ai trouvée plus rapide pour utiliser grep dans la recherche (en particulier pour changer de modèle) dans un seul fichier volumineux consiste à utiliser split + grep + xargs avec son drapeau parallèle. Par exemple:

Avoir un fichier d'identifiants que vous souhaitez rechercher dans un gros fichier appelé my_ids.txt Nom de bigfile bigfile.txt

Utilisez split pour scinder le fichier en plusieurs parties:

# Use split to split the file into x number of files, consider your big file
# size and try to stay under 26 split files to keep the filenames 
# easy from split (xa[a-z]), in my example I have 10 million rows in bigfile
split -l 1000000 bigfile.txt
# Produces output files named xa[a-t]

# Now use split files + xargs to iterate and launch parallel greps with output
for id in $(cat my_ids.txt) ; do ls xa* | xargs -n 1 -P 20 grep $id >> matches.txt ; done
# Here you can tune your parallel greps with -P, in my case I am being greedy
# Also be aware that there's no point in allocating more greps than x files

Dans mon cas, cela réduisait ce qui aurait été un travail de 17 heures en un travail de 1 heure et 20 minutes. Je suis sûr qu'il existe une sorte de courbe en cloche sur l'efficacité et qu'il est évident que passer en revue les cœurs disponibles ne vous sera d'aucun bien, mais c'était une bien meilleure solution que tous les commentaires ci-dessus pour mes besoins, comme indiqué ci-dessus. Cela présente un avantage supplémentaire par rapport au script parallèle en utilisant principalement des outils natifs (linux).

1
user6504312

cgrep, s'il est disponible, peut être beaucoup plus rapide que grep.

0
xhtml

MCE 1.508 inclut un script d'encapsuleur {fichier, liste} de niveau chunk double prenant en charge de nombreux binaires C; consentp, grep, egrep, fgrep et tre-consentp.

https://metacpan.org/source/MARIOROY/MCE-1.509/bin/mce_grep

https://metacpan.org/release/MCE

Il n'est pas nécessaire de convertir en minuscules pour vouloir que -i s'exécute rapidement. Passez simplement --lang = C à mce_grep.

L'ordre de sortie est préservé. Les sorties -n et -b sont également correctes. Malheureusement, ce n'est pas le cas pour GNU parallèle mentionné sur cette page. J'espérais vraiment GNU Parallèle pour fonctionner ici. De plus, mce_grep le fait pas sous-shell (sh-c/chemin/à/grep) lors de l'appel du binaire.

Une autre alternative est le module MCE :: Grep inclus avec MCE.

0
Mario Roy

Un léger écart par rapport au sujet initial: les utilitaires de ligne de commande de recherche indexés du projet googlecodesearch sont bien plus rapides que grep: https://github.com/google/codesearch :

Une fois que vous l'avez compilé (le paquetage golang est nécessaire), vous pouvez indexer un dossier avec:

# index current folder
cindex .

L'index sera créé sous ~/.csearchindex

Maintenant, vous pouvez rechercher:

# search folders previously indexed with cindex
csearch eggs

Je continue de passer les résultats dans grep pour obtenir des correspondances colorisées.

0
ccpizza