Ripgrep : un outil de recherche plus rapide que grep, ag, Git grep, etc. (2016)
(blog.burntsushi.net)- ripgrep (
rg) est un outil de recherche en ligne de commande basé sur Rust qui combine la commodité de recherche dans le code à la The Silver Searcher avec des performances brutes du niveau de GNU grep, et propose des binaires pour Linux, Mac et Windows - Sur 25 benchmarks, aucun outil ne devançait clairement
ripgrepen performances et en précision, aussi bien sur un gros fichier unique que sur la recherche dans de grands répertoires, et le coût de la prise en charge d’Unicode restait faible - Avec la gestion de
.gitignore, l’exclusion par défaut des fichiers cachés et binaires, les filtres par type de fichier, la prise en charge optionnelle de PCRE2, la recherche dans plusieurs encodages et fichiers compressés, ainsi que les filtres de prétraitement, il élargit le champ d’usage réel des outils de recherche dans le code - Les écarts entre les expériences sur le dépôt du noyau Linux et OpenSubtitles2016 dépendent fortement de l’optimisation des littéraux, de la recherche multi-motifs SIMD Teddy, d’Aho-Corasick, de la méthode de décodage UTF-8, du comptage des lignes et du coût de traitement de
.gitignore - Lors d’une recherche parallèle dans de nombreux petits fichiers, le mapping mémoire peut être plus lent, tandis qu’il peut être avantageux sur un seul gros fichier ;
ripgreputilise donc selon le contexte soit une recherche avec tampon intermédiaire, soit une recherche par mapping mémoire
La position visée par ripgrep
ripgrepest un outil de recherche en ligne de commande qui vise à réunir la commodité des outils de recherche dans le code et les performances des outils de typegrep- Les outils comparés sont
GNU grep,git grep,The Silver Searcher (ag),Universal Code Grep (ucg),The Platinum Searcher (pt)etsift - Les benchmarks cherchent à vérifier trois points essentiels
- Aucun outil n’est clairement supérieur à
ripgrep, que ce soit pour rechercher dans un fichier unique ou dans un grand répertoire - Il offre une vraie prise en charge d’Unicode sans imposer un coût important en performances
- Lorsqu’on recherche dans plusieurs fichiers à la fois, le mapping mémoire peut généralement être plus lent plutôt que plus rapide
- Aucun outil n’est clairement supérieur à
- L’auteur est aussi le créateur de
ripgrepet du moteur d’expressions régulières sous-jacent, et indique que les benchmarks peuvent être sélectionnés et donc biaisés
Fonctionnalités et comportement par défaut
- Le nom de l’exécutable de
ripgrepestrg - Par défaut, la recherche parcourt récursivement le répertoire courant, respecte
.gitignoreet ignore les fichiers cachés et binaires .rgignoreest également pris en charge, et les motifs de.rgignoresont prioritaires sur ceux de.gitignore-u,-uuet-uuupermettent d’élargir progressivement le périmètre en ignorant les fichiers ignore, en incluant les fichiers cachés puis en incluant les fichiers binairesrg -uuuest similaire àgrep -a -r
- Les filtres par type de fichier sont pris en charge
rg -tpy foo: rechercher uniquement dans les fichiers Pythonrg -Tjs foo: exclure les fichiers JavaScript--type-addpermet d’ajouter de nouvelles règles de type de fichier
- Plusieurs fonctionnalités de
grepsont aussi disponibles- Affichage du contexte
- Recherche de plusieurs motifs
- Coloration des correspondances
- Prise en charge complète d’Unicode
- Le moteur d’expressions régulières par défaut ne prend pas en charge les assertions look-around ni les backreferences, mais ces fonctionnalités deviennent disponibles en sélectionnant le moteur PCRE2 avec
-P - Une détection automatique partielle de l’UTF-16 et la spécification de l’encodage via
-E/--encodingsont également prises en charge- Cela inclut UTF-16, latin-1, GBK, EUC-JP, Shift_JIS, etc.
-z/--search-zippermet de rechercher dans des fichiers compressés comme gzip, xz, lzma, bzip2 ou lz4- Des filtres de prétraitement arbitraires sont aussi pris en charge, par exemple l’extraction de texte depuis des PDF, la décompression supplémentaire, le déchiffrement ou la détection automatique de l’encodage
Raisons de ne pas l’utiliser
- Si la portabilité et la disponibilité partout sont la priorité absolue, grep, standard et largement installé, est le choix approprié
- Si l’on dépend d’une fonctionnalité particulière ou d’un bug présent dans un autre outil,
ripgreppeut ne pas convenir - Dans certains cas limites de performance, d’autres outils peuvent mieux se comporter
- Il peut aussi être inutilisable s’il ne peut pas être installé ou si la plateforme n’est pas prise en charge
Structure de fonctionnement des outils de type grep
- Un outil de recherche passe grosso modo par trois étapes
- Collecte des fichiers à rechercher
- Recherche proprement dite
- Affichage des résultats
- Les outils de type
grepdoivent bien rechercher dans de gros fichiers, ce qui rend les performances du moteur d’expressions régulières importantes - Les outils de type
ackdoivent traiter rapidement le parcours récursif des répertoires et l’application de règles d’ignore comme.gitignore ripgrepcherche à combiner les deux approches- Moteur d’expressions régulières rapide
- Recherche parallèle
- Filtrage des cibles de recherche
Collecte des fichiers et traitement des ignore
- Dans les outils de type
ack, il est important de décider rapidement quels fichiers rechercher à partir du répertoire courant - Les performances du parcours des répertoires dépendent du nombre d’appels
statinutiles ripgreputilise un itérateur récursif de répertoires qui vise un nombre minimal d’appels système- Le traitement de
.gitignorea un coût- Il faut chercher les fichiers ignore dans chaque répertoire
- Il faut compiler les motifs d’ignore
- Il faut appliquer les motifs à tous les chemins candidats
- Le dépôt du noyau Linux contenait 4 640 répertoires et 178 fichiers
.gitignore ripgrepcherche à prendre en charge plus complètement la sémantique de.gitignore, et donne la priorité au motif correspondant défini le plus récemmentucgpeut être rapide parce qu’il utilise des règles glob fondées sur une liste blanche plutôt que.gitignore, mais il risque de manquer des fichiers dont l’extension lui est inconnue
Différences entre moteurs d’expressions régulières
- Les moteurs d’expressions régulières se divisent généralement en deux catégories
- Basés sur le backtracking : riches en fonctionnalités, mais peuvent devenir exponentiellement lents sur certaines entrées
- Basés sur les automates finis : fonctionnalités parfois limitées, mais garantissent un temps linéaire par rapport à la longueur du texte recherché
- Les moteurs par outil sont les suivants
- GNU grep,
git grep: moteurs internes basés sur des automates finis ripgrep: bibliothèque regex de Rust, basée sur des automates finisag,ucg: backtracking basé sur PCREpt,sift: bibliothèque regex de Go, basée sur des automates finis
- GNU grep,
agetucg, du fait de leur utilisation de PCRE, peuvent être exposés aux pires comportements du backtracking- Le motif d’exemple
(a*)* cpeut poser problème aux outils basés sur PCRE, alors que les autres outils du benchmark le traitent sans difficulté
Optimisation des littéraux et SIMD
- Dans une recherche de chaîne simple, l’optimisation de la recherche de littéraux peut devenir plus importante que le moteur d’expressions régulières
- Boyer-Moore est un algorithme classique de recherche de sous-chaîne, qui peut exploiter des routines comme
memchrpour trouver rapidement les positions candidates - Les implémentations de
memchrexaminent souvent 16 octets à la fois avec des instructions SIMD, et peuvent atteindre un débit de plusieurs Go/s - La bibliothèque regex de Rust extrait activement les littéraux de préfixe et de suffixe dans les motifs
foo|bar(a|b)c[ab]foo[yz](foo)?bar(foo)*bar(foo){3,6}
- Si l’expression régulière complète peut être décomposée en un seul littéral ou en une alternance de littéraux, le moteur principal d’expressions régulières peut ne pas être utilisé du tout
ripgrepexploite la nature de l’affichage des résultats ligne par ligne pour extraire aussi des littéraux internes- Exemple : dans
\w+foo\d+, il cherche d’abordfoo, puis vérifie uniquement les lignes candidates avec l’expression régulière
- Exemple : dans
- Pour la recherche de plusieurs littéraux, GNU grep utilise un algorithme proche de Commentz-Walter, tandis que regex de Rust utilise Aho-Corasick ou l’algorithme SIMD Teddy
- Teddy est un algorithme de recherche multi-motifs basé sur SIMD issu d’Intel Hyperscan, et constitue l’une des optimisations clés qui permettent à
ripgrepde devancer GNU grep
Méthode de recherche : éviter la recherche ligne par ligne
- Une implémentation naïve lit le fichier ligne par ligne et applique le motif à chaque ligne, mais c’est inefficace dans la plupart des recherches, car les correspondances sont rares
- Les outils de recherche parcourent généralement de grands tampons d’octets d’un coup
- Mapping du fichier en mémoire
- Lecture du fichier entier en mémoire
- Recherche progressive avec un tampon intermédiaire de taille fixe
ripgrep, GNU grep etgit grepprennent en charge la recherche progressive, applicable aussi bien aux fichiers qu’aux flux- La recherche progressive est difficile à implémenter
- Calcul des numéros de ligne
- Gestion des cas où le tampon se termine au milieu d’une ligne
- Gestion des lignes longues
- Traitement d’invert match
- Affichage du contexte autour des correspondances
ripgrepaccepte cette complexité d’implémentation et utilise la recherche progressive ; dans les benchmarks, elle se montre plus rapide que le mapping mémoire lors de la recherche dans de nombreux petits fichiers
Sortie et parallélisme
- Dans une recherche parallèle, si chaque thread écrit directement sa sortie, les résultats provenant de fichiers différents peuvent se mélanger
- Tous les outils de recherche de code parallèles écrivent les résultats de recherche dans un tampon intermédiaire en mémoire, et ne sérialisent que l’étape de sortie
- Cette approche permet aux threads de recherche d’effectuer la recherche proprement dite en parallèle
- Son inconvénient est qu’elle peut entraîner une forte consommation mémoire dans des cas comme un fichier de 2 Go où toutes les lignes correspondent
ripgrepécrit directement dansstdout, sans tampon intermédiaire, lors d’une recherche surstdinou sur un seul fichier
Méthodologie des benchmarks
- Les benchmarks sont répartis selon les problèmes rencontrés par l’utilisateur final
- Recherche dans de grands dépôts de code
- Recherche dans un seul gros fichier
- Les motifs de recherche privilégient les littéraux simples, les alternations et les expressions régulières légères
- Comme le comportement par défaut varie selon les outils, les conditions telles que les numéros de ligne, Unicode,
.gitignoreet les listes blanches ont été alignées autant que possible pour une comparaison équitable - Les versions testées sont les suivantes
ripgrepv0.1.2- GNU grep v2.25
git grepv2.7.4agcommitcda635, PCRE 8.38ucgcommit487bfb, PCRE 10.21 JITptcommit509368siftcommit2d175c
acka été exclu, car il était alors nettement plus lent que les autres outils- Le runner de benchmark est
benchsuite, qui nécessite Python 3.5 ou ultérieur, et il est inclus dans le dépôtripgrep - Chaque commande exécute 3 warm-ups avant la mesure afin que le corpus soit chargé dans le page cache de l’OS
- Chaque commande est mesurée 10 fois, puis la moyenne et l’écart type sont enregistrés
- L’environnement d’exécution est Amazon EC2
c3.2xlarge, Ubuntu 16.04, Xeon E5-2680 2,8 GHz, 16 Go de mémoire et un SSD de 80 Go - Les logs de configuration, les résultats récapitulatifs et les CSV bruts ont également été publiés
Résultats de recherche dans le code du noyau Linux
- Le benchmark de recherche de code a été exécuté sur le dépôt du noyau Linux compilé, au commit
d0acc7 - Le dépôt du noyau compilé a été utilisé parce que les artefacts de build restant dans le dépôt peuvent affecter la pertinence des résultats et les performances
- Dans
linux_literal_default, la recherche du littéral simplePM_RESUMEmet en évidence les différences de comportement par défaut de chaque outilrgrespecte.gitignoreet ignore les fichiers cachés et binairesagetptsont similaires, mais comptent le nombre de lignesucgne lit pas.gitignoreet effectue une recherche fondée sur une liste blanchesiftrecherche par défaut presque partoutgit grepbénéficie de l’obtention de l’ensemble des fichiers à rechercher depuis l’index git
- Le respect de
.gitignoreaméliore la pertinence des résultats, mais peut avoir un coût en performances - Dans
linux_literal,rg (whitelist)a affiché des performances presque similaires àucg, tandis querg (ignore)était à un niveau comparable àgit grep rg (ignore) (mmap)etag (ignore) (mmap)ont été ralentis par l’utilisation du memory mapping, et, à conditions identiques,rg (ignore)était beaucoup plus rapide- Sur une machine locale également, les versions utilisant le memory mapping étaient plus lentes, mais l’écart était moindre que sur EC2
Unicode et recherche insensible à la casse
- Dans
linux_literal_casei,ptralentit fortement en traitant-icomme(?i)de la regexp Go siftralentit moins grâce à une approche consistant à convertir le motif et les blocs de recherche en minuscules, mais cette optimisation ne gère que la casse ASCII et est donc incorrecte pour la casse Unicoderipgreptransforme les recherches insensibles à la casse en combinaisons de littéraux possibles, puis utilise Teddy pour trouver rapidement les positions candidates- La recherche
\wAhdanslinux_unicode_wordvérifie si\w, avec prise en charge Unicode, capture des résultats commeµAh - Seuls
rgetgit greppermettaient de basculer Unicode ;ag,pt,siftetucgutilisaient un\wlimité à l’ASCII git grepsubissait un coût de performance important lorsque la prise en charge Unicode était activée, tandis queripgrepne connaissait presque aucune baisse de performancesripgrepintègre le décodage UTF-8 dans une machine à états finis et effectue la correspondance directement sur les chaînes d’octets UTF-8, sans étape de décodage séparée
Écarts selon la complexité des expressions régulières
- Pour les expressions régulières avec un suffixe littéral, comme
[A-Z]+_RESUME,rgetucgutilisent_RESUMEpour trouver rapidement les candidats - Pour les alternations de littéraux comme
ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,ripgreputilise Teddy et peut ne pas utiliser du tout le moteur regex principal - Même pour les alternations insensibles à la casse,
ripgrepgénère des préfixes combinant les variantes de casse, trouve les candidats avec Teddy, puis ne valide que ces candidats avec l’expression régulière complète - Pour la recherche
\p{Greek}, seuls Rust regex et Go regex prenaient en charge cette propriété Unicode, etrgétait beaucoup plus rapide queptetsift - Dans la recherche insensible à la casse
\p{Greek},siftn’a signalé aucune correspondance, etptne gérait pas correctement la casse Unicode - Pour les motifs sans littéral, comme
\w{5}\s+..., les performances du moteur regex apparaissent directementrgrestait plutôt rapide même avec la prise en charge Unicode activéegit grepsubissait un coût important avec la prise en charge Unicode- Le DFA Unicode manipule un ensemble d’états NFA bien plus grand que le DFA ASCII ; les chiffres d’exemple sont d’environ 250 états NFA pour l’ASCII contre environ 77 000 pour Unicode
Recherche dans un seul gros fichier
- Le benchmark sur fichier unique utilise un échantillon d’OpenSubtitles2016
- L’échantillon anglais fait environ 1 Go
- L’échantillon russe fait environ 1,6 Go
- Dans ce domaine, les performances du moteur regex et les optimisations de littéraux deviennent plus importantes
- Dans
subtitles_literal,rgétait le plus rapide pour les recherchesSherlock HolmescommeШерлок Холмс ripgrepessaie de choisir des octets rares dans les littéraux pour les utiliser avecmemchr- Une implémentation standard de Boyer-Moore utilise généralement le dernier octet pour rechercher les candidats
rgessaie de choisir un octet plus rare afin de sauter plus longtemps dans la boucle optimisée SIMD
- Pour les motifs russes, de nombreux caractères commencent en UTF-8 par
\xD0ou\xD1, ce qui peut rendre la recherche sur le premier octet inefficace rgutilise une table de fréquences précalculée de 256 octets pour privilégier des octets plus rares que\xD0et\xD1- Dans un seul gros fichier, comme il suffit de créer le memory mapping une seule fois, la recherche avec memory mapping de
rgétait environ 25 % plus rapide querg (no mmap)
Unicode et alternation dans un fichier unique
- Dans
subtitles_literal_casei,rgreste rapide tout en gérant correctement la recherche Unicode insensible à la casse - GNU grep subit un coût important dans les recherches Unicode insensibles à la casse
- Dans la recherche russe insensible à la casse,
grep (ASCII)semble ignorer-idans les faits, etagsignale 0 correspondance - Dans
subtitles_alternate, la recherche par alternation de plusieurs noms de personnages était la plus rapide avecrg, aussi bien en anglais qu’en russe - Pour l’alternation en anglais,
rgétait environ un ordre de grandeur plus rapide que GNU grep - Dans
subtitles_alternate_casei,rgétait beaucoup plus lent qu’auparavant, mais devançait les autres outils en anglais - Dans ce cas, le nombre de candidats littéraux devient trop élevé pour Teddy, et
rgbascule donc vers Aho-Corasick ripgreputilise l’Aho-Corasick « advanced » basé sur une table de transitions, qui effectue une transition par octet d’entrée
Littéral interne et motifs sans littéral
- Un motif comme
\w+\s+Holmes\s+\w+est conçu pour éviter les optimisations par littéral de préfixe ou de suffixe, mais il peut exploiter le littéral interneHolmes ripgrepet GNU grep effectuent une optimisation par littéral interneripgreputiliseregex-syntaxde Rust regex pour extraire les littéraux de l’AST du motif- Dans la version russe
\w+\s+Холмс\s+\w+, seuls les outils prenant correctement en charge Unicode pouvaient produire des résultats pertinents - Pour un long motif sans aucun littéral, du type
\w{5}\s+...,rgfaisait partie des plus rapides en anglais, tandis que la version de GNU grep avec prise en charge d’Unicode a été exclue, car elle prenait plus de 90 secondes en anglais et plus de 4 minutes en russe ripgrepmaintient la prise en charge d’Unicode tout en conservant de bonnes performances en intégrant le décodage UTF-8 dans le DFA
Benchmarks supplémentaires
everythingest un test peu réaliste qui fait correspondre toutes les lignes du dépôt Linux avec.*rgsignale 22 065 361 lignes en 1,081 secondeagetptne signalent pas toutes les lignes, ce qui laisse penser qu’ils appliquent une limite de correspondances
nothingest un test qui applique un invert match à.*afin de ne signaler aucune lignergobtient 0,302 seconde, contre 0,905 seconde pourgit grepptetucgne prennent pas en charge la recherche inversée
contextaffiche 2 lignes de contexte autour deSherlock Holmesdans le corpus de sous-titres anglaisrgobtient 0,612 seconde, un résultat proche desiftavec 0,717 secondeucgne prend pas cette fonctionnalité en charge
hugerechercheSherlock Holmesdans l’ensemble des sous-titres anglais, soit 9,3 Gorgobtient 1,786 seconde, GNU grep 5,119 secondes etsift3,047 secondesucgn’a signalé que 1 543 lignes avec l’option de comptage des lignes, produisant un résultat incorrect ; on soupçonne un problème lors de la recherche dans des fichiers de plus de 2 Go
Conclusion
ripgrepn’a pas remporté systématiquement tous les benchmarks de recherche dans le dépôt du noyau Linux, mais il était difficile d’affirmer qu’un autre outil lui était clairement supérieur en performances et en exactitudegit greppouvait devancer de quelques millisecondes dans certains cas simples, mais lorsque les motifs devenaient plus complexes ou qu’Unicode était requis,ripgreppouvait prendre une avance importante- Les éléments suivants contribuent aux performances de
ripgrepdans la recherche de code- Parcours rapide des répertoires visant à minimiser les appels
stat - Correspondance des globs
.gitignoreavecRegexSet - Répartition du travail via une file Chase-Lev de work stealing
- Choix de ne pas utiliser de mémoire mappée pour rechercher dans de nombreux petits fichiers
- Moteur d’expressions régulières rapide
- Parcours rapide des répertoires visant à minimiser les appels
- Pour la recherche dans un fichier unique,
ripgrepest le plus rapide ou prend une avance nette dans tous les principaux benchmarks - Les performances sur fichier unique sont influencées par
memchrbasé sur des octets rares, Teddy SIMD, Aho-Corasick et le DFA intégrant le décodage UTF-8 - Dans les benchmarks nécessitant des fonctionnalités Unicode, seuls
rg, GNU grep etgit grepoffraient une prise en charge significative ; GNU grep etgit greppayaient généralement un coût de performance élevé - Sur Linux x86_64, la mémoire mappée était défavorable pour la recherche parallèle dans de nombreux petits fichiers, avantageuse pour la recherche dans un seul gros fichier, et pouvait entraîner une pénalité supplémentaire dans les environnements VM
1 commentaires
Avis de Hacker News
C’est clairement rapide, et je continue de recommander la combinaison avec fzf
Je m’en sers via une fonction PowerShell qui cherche d’abord avec
ripgrep, ajoute ensuite une recherche floue sur les fichiers+textes des résultats, puis affiche le contexte avecbatDans des projets mélangeant plusieurs dépôts, ça permet de réduire très vite le champ quand « on sait que c’est quelque part, mais sans connaître l’emplacement exact ni le nom »
Cette méthode vient de https://github.com/junegunn/fzf/blob/master/ADVANCED.md et, même sans tout utiliser, ça vaut le coup de la parcourir pour s’en inspirer
fzfOn peut faire de la recherche floue non seulement dans les fichiers texte, mais aussi dans divers formats comme les PDF ou les zip
Les détails sont ici : https://github.com/phiresky/ripgrep-all/wiki/fzf-Integration
Elle consiste à sélectionner un résultat de
rgavecfzf, puis à analyser le fichier et le numéro de ligne choisis pour l’ouvrir avec$EDITOR +"${linenumber}" "$file"C’est comme moudre son café à la main au lieu d’utiliser un moulin électrique
fzf, on peut sélectionner beaucoup de fichiers à ajouter à Git tout en en ignorant certainsEn mettant
fza = "!git ls-files -m -o --exclude-standard | fzf -m --print0 | xargs -0 git add"dans[alias]degitconfig,git fzaaffiche la liste des fichiers modifiés ou pas encore ajoutés, et on peut basculer les éléments avec Espace en passant au suivantCet alias et fzf+fd accélèrent pas mal une partie du flux de travail
Il existe aussi un guide qui récapitule des éléments à mettre dans la configuration zsh sur macOS : https://gist.github.com/aclarknexient/0ffcb98aa262c585c49d4b...
ripgreppresque de la même manièreJe m’en sers comme point de départ pour réduire la recherche à un fichier ou un projet dans une base de code contenant des centaines de dépôts, puis je creuse davantage
Dans Emacs, j’utilise
ripgrepavec project.el et le paquet dumb-jumpCe n’est peut-être pas l’approche la plus populaire, mais l’expérience globale est assez satisfaisante
Il suffit d’installer
dumb-jumpavecpackage-installet de configurer seulement(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)Dans un projet Python, quand on cherche la définition d’un identifiant avec
M-.ouC-u M-.,dumb-jumpexécute une commandergadaptée au projet courant et au type de fichier, puis affiche les résultats dans le tampon Xrefagest aussi pris en charge et, s’il n’y a niagnirg, il retombe surgrep, ce qui peut être lent comme prévu quand on cherche dans tout le répertoire personnelripgrepassez facilementUn paquet externe n’est pas indispensable ; pour l’utiliser à la place du lent
grepdans de grands répertoires, il suffit de définir(setq xref-search-program 'ripgrep)Une recherche de projet comme
C-x p g foo RETs’exécute alors dans le projet courant sous une forme du genrerg -i --null -nH --no-heading --no-messages -g '!*/' -e fooLes résultats s’affichent dans le tampon Xref, ce qui rend pratiques les touches comme
n,p,RET,C-opour passer au résultat suivant/précédent, sauter vers la source ou afficher dans une fenêtre diviséeripgrep, à première vue, je n’ai pas exécuté cette expression régulière moi-même, mais il me semble qu’on peut retirer le drapeau --pcre2Les deuxième et troisième assertions
\bpeuvent aussi probablement être retirées, la première pouvant être nécessaireripgrepet propose aussi des raccourcisevil-collection, ce qui le rend agréable à utiliser : https://github.com/Wilfred/deadgrepC’est le genre de situation où j’aurais auparavant utilisé
rgrepCe qui est intéressant, c’est que la recherche de VS Code fonctionne désormais elle aussi avec
ripgrepvia un wrapper Node.jshttps://www.npmjs.com/package/@vscode/ripgrep
ripgrep, c’est très pratiqueOn peut trouver le binaire
rgdans le chemin d’installation de VS. En tout cas, c’était possible dans mon environnement Windows au travailJ’utilise
ripgrepdepuis environ deux ans, et c’est devenu un outil indispensableLa principale raison pour laquelle j’ai quitté
grepétait la facilité d’utilisationPar défaut, il respecte les règles de
.gitignoreet ignore les fichiers/répertoires cachés ainsi que les fichiers binaires ;rg search_term directoryest donc bien meilleur que la commandegrepéquivalente, et le gain de vitesse est un bonusQuand une correspondance est trop longue et met le bazar dans le terminal, j’utilise souvent l’option -M, par exemple
-M 1000-Mest vraiment excellentC’est particulièrement pratique pour ignorer les résultats de fichiers minifiés qu’on ne veut pas voir, et l’option -g pour ne chercher que dans les fichiers d’une certaine extension, comme
-g *.cs, est très bien aussiLe fait que ce soit un binaire autonome et portable est également utile : quand je travaille sur une nouvelle machine, je mets l’exécutable et je définis l’alias
grepversrg, comme ça même si je tapegreppar habitude, c’estrgqui s’exécuteC’est peut-être toujours vrai en 2023, mais le problème est que les remplaçants parallélisés de
grep, commeripgrepouag, sont tellement plus rapides que legrepclassique que les petits écarts de vitesse entre eux deviennent difficiles à prendre comme critère de distinction.J’utilise
agdans Emacs sur une base de code de 900 000 lignes, et sur un Ryzen Threadripper 2950X à 16 cœurs, ça se termine quasiment instantanément.Je ne ressens pas le besoin de réduire un temps inférieur à 1 seconde à « un peu plus inférieur à 1 seconde ».
La caractéristique essentielle des nouveaux outils de type
grepn’est pas la vitesse ; il faut les évaluer et les comparer autrement.aga une falaise de performance assez nette, et on le voit aussi dans l’article de blog.Cela dit, les charges de travail varient selon les personnes, donc dans certains cas les différences de performance peuvent ne pas compter.
900 000 lignes, ce n’est pas particulièrement gros, et pour une requête simple, la plupart des outils de type
grepqui ne sont pas naïfs traitent ça très vite.Si l’on regarde d’autres critères de comparaison,
agest pratiquement sous assistance respiratoire ; il a failli être retiré de Debian avant que quelqu’un ne le sauve, semble-t-il : https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=999962L’article de blog compare aussi la prise en charge d’Unicode ;
ag, en pratique, n’a pas vraiment de prise en charge d’Unicode. Ce ne sera pas important pour tout le monde, mais c’est un critère non lié à la performance tout à fait valable.Le temps de recherche correspond au temps nécessaire pour charger les fichiers depuis le disque, et les différences après ça ont peu de chances d’être significatives.
Si les fichiers sont en cache, le temps passé à parcourir le système de fichiers et à taper la commande domine davantage que le temps de recherche, donc là encore les écarts de performance ont peu de chances d’être significatifs.
Le titre a besoin de (2016).
C’est le billet d’annonce d’origine, pas une nouvelle information.
« Ripgrep – A new command line search tool » https://news.ycombinator.com/item?id=12564442 (740 points | 23 sept. 2016 | 209 commentaires) — il y a aussi des discussions sur la vitesse.
« Ripgrep is faster (2016) » https://news.ycombinator.com/item?id=17941319 (98 points | 8 sept. 2018 | 40 commentaires)
Ce n’est pas plus rapide que
qgrep.Les deux fonctionnent très différemment, et
qgrepest basé surre2, mais sa vitesse vient de l’index.Sur de gros dépôts de fichiers, utiliser
qgrepet un index plutôt que de parcourir tous les fichiers à chaque fois paraît plus logique ; je me demande pourquoi les gens oublient l’optionqgrep.Cela dit, si vous avez besoin de correspondances multilignes en UTF-8,
ripgrepdoit basculer sur une autre bibliothèque PCRE2, donc je ne pense pas que ce soit aussi rapide.ripgrep, oui,qgrepa un avantage sur les outils qui n’indexent pas, puisqu’il utilise l’indexation.En contrepartie, il faut configurer et maintenir l’index, donc l’UX n’est pas aussi simple que « lancer simplement une recherche ».
La raison pour laquelle les gens n’utilisent pas
qgrepressemble à celle pour laquelle ils n’utilisent pasripgrepen se disant « grep est déjà assez rapide pour moi ».Sur de petites cibles de recherche, on ne perçoit souvent pas la différence de vitesse entre
ripgrepetgrep, ou entreqgrepetripgrep.Si
ripgreptermine une recherche dans le noyau Linux en moins de 100 ms, il est discutable, mais généralement peu probable, que ce soit assez pénible dans un usage interactif standard pour passer à un outil indexé.J’ai déjà réfléchi à l’idée d’ajouter l’indexation à
ripgrep: https://github.com/BurntSushi/ripgrep/issues/1497Et la recherche multilignes n’exige pas PCRE2. Le moteur d’expressions régulières par défaut prend aussi en charge Unicode, et même une compilation sans PCRE2 conserve la prise en charge de la recherche multilignes.
Depuis que je suis passé de
ripgrepà ugrep, je n’ai pas fait marche arrière.La vitesse est comparable, mais il y a la correspondance approximative, une TUI utilisable pour les revues de code, et la possibilité de chercher dans les PDF ou les fichiers compressés.
Le fait de pouvoir utiliser en option la syntaxe de recherche Google est aussi pratique.
https://ugrep.com
ripgrep, mais récemment j’ai découvertugrepà cause d’une fonctionnalité absente deripgrep: la recherche à l’intérieur des archives zip.On peut chercher sans décompresser sur le disque.
Je travaille avec des corpus compressés composés de millions de petits fichiers texte, et c’est appréciable de ne plus avoir à tout extraire dans le système de fichiers. Certains systèmes de fichiers souffrent à cette échelle.
Je suis reconnaissant envers les deux outils, et envers chacun de leurs auteurs.
grepcommence à utiliser la syntaxe de recherche Google, la plupart des résultats essaient de me vendre quelque chose.ugrepetripgrepse sont disputés pendant des années sur Reddit.Par exemple https://www.reddit.com/r/programming/comments/120wqvr/ripgre...
C’est juste une discussion sur des outils open source, mais ça m’a paru un peu bizarre.
fzf.Pour moi, il paraît difficile de battre la configurabilité et la souplesse de
fzf.La fonctionnalité décisive semble être la compatibilité avec les options en ligne de commande de grep existantes.
C’est plutôt appréciable de ne pas avoir à apprendre un tout nouvel ensemble d’options.
Je me demande pourquoi
grepn’est pas remplacé ou amélioréCe sujet commence lui aussi à dater un peu
L’inertie, la compatibilité, la résistance au changement, le dilemme de l’innovateur, etc. Je ne dis pas ça de manière négative, tout cela s’applique aussi à moi
Pour la compatibilité, voir la FAQ : https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#pos...
Elle est confortable, s’intègre bien à mon environnement de travail, et je n’ai pas de raison de la remplacer puis de tout réadapter
La comparaison ne va pas plus loin que le fait qu’une chaise comme la Razer est déjà dans les parages et sert à poser des vêtements
xyz, qui accepte tel argument et se comporte exactement de cette façon »ripgrepS’il s’agit de remplacer la commande
grepelle-même par un autre utilitaire, il semble qu’on casserait trop de choses pour le bénéfice obtenuLes personnes qui veulent un
grepplus rapide peuvent utiliser un autre outil, et celles qui utilisent legrepexistant peuvent continuer à le faire ; on est donc déjà proche d’un état idéalgrepest un outil généraliste pour trouver du texte dans toutes sortes de fichiers, et il est inscrit dans le standard UNIXCertains programmeurs l’utilisent pour chercher dans du code source, mais d’autres s’en servent pour des recherches de texte sans rapport avec le code source ou dans des scripts, et s’attendent à ce qu’il ne plante jamais
À l’inverse,
ripgrepest un outil spécialisé et très orienté, principalement conçu pour rechercher dans des dépôts de code sourceIl n’y a pas énormément de marge pour accélérer une recherche de texte généraliste. Utiliser
mmap()expose à un risque de crash sur des fichiers tronqués ; réduire l’expressivité des expressions régulières pourrait accélérer les choses ; on pourrait aussi abandonner la prise en charge de toutes les locales et jeux de caractères pour ne coder en dur qu’UTF-8/UTF-16, mais ce ne serait pas acceptableEn regardant dans Portage, il semble qu’il existe aussi une version qui traite d’autres types de documents comme les PDF et les fichiers doc
https://github.com/phiresky/ripgrep-all