Introduction
Linux · Performance · Outils CLI
Chercher du texte dans des fichiers, c’est le pain quotidien du sysadmin et du développeur. grep règne depuis 1974, mais ripgrep (rg) a révolutionné la vitesse de recherche. Ce comparatif couvre les benchmarks réels, les différences de comportement et les cas d’usage concrets pour choisir le bon outil.

grep vs ripgrep : les fondamentaux
grep — l’incontournable depuis 1974
Écrit par Ken Thompson en 1974, grep (Global Regular Expression Print) est un pilier d’Unix. Présent dans tout système POSIX (Linux, BSD, macOS, conteneurs Alpine, BusyBox), il est garanti disponible partout. GNU grep, la version standard sur Linux, utilise le moteur regex PCRE (ou POSIX étendu par défaut) et supporte les options classiques : -r (récursif), -n (numéros de ligne), -l (noms de fichiers), -E (extended regex).
ℹ️ Info — Philosophie POSIX
grep suit la philosophie Unix : faire une chose, la faire bien. Il lit depuis stdin ou des fichiers, respecte les conventions POSIX, et s’intègre dans n’importe quel pipeline. C’est pour ça qu’on le retrouve dans les Dockerfiles, les scripts de CI et les crons depuis 50 ans.
ripgrep — la recherche réinventée en Rust
ripgrep (rg), créé par Andrew Gallant (BurntSushi) en 2016, est un outil de recherche récursif écrit en Rust. Il vise à remplacer grep pour la recherche de code avec plusieurs innovations majeures :
- Parallélisme automatique — utilise tous les cœurs CPU disponibles
- Respect du .gitignore — ignore les fichiers exclus par défaut
- Mémoire-mapping (mmap) — lecture optimisée des fichiers
- Ignore les binaires et les fichiers cachés — comportement intelligent par défaut
- Moteur regex Rust — basé sur un DFA/SIMD, sans backtracking catastrophique
Disponible via apt install ripgrep, dnf install ripgrep ou cargo install ripgrep.
Table comparative détaillée
Benchmarks : performances réelles
Les benchmarks ont été effectués sur les sources du noyau Linux v6.12 (~80 000 fichiers, ~1.2 Go). Machine : 8 cœurs, 16 Go RAM, SSD NVMe, Debian 13.
# Recherche simple : "CONFIG_NET"
$ time grep -r "CONFIG_NET" linux-6.12/ 2>/dev/null | wc -l
42713
real 0m3.842s
user 0m3.214s
sys 0m0.628s
$ time rg "CONFIG_NET" linux-6.12/ | wc -l
42713
real 0m0.187s
user 0m1.412s
sys 0m0.234s
# Recherche avec contexte : "Kconfig" + 2 lignes avant/après
$ time grep -rn -C2 "source \"arch" linux-6.12/ 2>/dev/null | wc -l
482
real 0m4.216s
$ time rg -C2 "source \"arch" linux-6.12/ | wc -l
482
real 0m0.098s
# Regex complexe : adresses email
$ time grep -rE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" linux-6.12/ 2>/dev/null | wc -l
842
real 0m5.127s
$ time rg -e "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" linux-6.12/ | wc -l
842
real 0m0.314s
💡 Astuce — Consommation mémoire
ripgrep utilise le memory-mapping (mmap) quand c'est possible, ce qui délègue la gestion mémoire au noyau. Résultat : la consommation RSS reste faible (~15-30 Mo) même sur des codebases de plusieurs Go, là où grep charge les fichiers en userspace.
Moteurs regex : POSIX vs Rust
La différence de performance entre grep et ripgrep ne vient pas que du parallélisme. Le moteur regex lui-même est fondamentalement différent.
GNU grep — PCRE avec backtracking
GNU grep utilise un moteur hybride : il tente d'abord un algorithme DFA (déterministe) pour les patterns simples, et bascule vers un NFA avec backtracking pour les expressions complexes (lookaheads, backreferences). Le problème : le backtracking peut être exponentiel sur certains patterns pathologiques (ReDoS).
ripgrep — moteur Rust regex
Le crate regex de Rust utilise un moteur DFA/SIMD très optimisé. Il compile le pattern en un automate déterministe quand c'est possible, et utilise des instructions SIMD (AVX2/SSE4.2) pour accélérer la recherche littérale. Conséquence : temps de recherche O(n) garanti, pas de backtracking catastrophique.
# Pattern pathologique (ReDoS) — arrêt après 10s pour grep
$ timeout 10 grep -rE '(a+)+$' /tmp/test-reDos/ 2>/dev/null
# Bloqué, timeout atteint
$ rg '(a+)+$' /tmp/test-reDos/
# Résultat instantané — pas de backtracking
⚠️ Attention — Limitation du moteur Rust
Le moteur regex de Rust ne supporte pas les backreferences (\1) ni les lookarounds. Pour ces cas, ripgrep propose le flag --pcre2 (si la lib pcre2 est disponible à la compilation) qui bascule vers le moteur PCRE2 — au prix d'une perte de performance.
Cas d'usage avancés
Respect du .gitignore
ripgrep ignore automatiquement les fichiers listés dans .gitignore, .ignore, .rgignore et les règles globales de git. grep, lui, cherche partout — y compris dans node_modules/, vendor/, .git/ et les fichiers build.
# grep cherche PARTOUT (y compris node_modules, .git...)
$ grep -r "import React" mon-projet/
# Résultats noyés dans le bruit
# rg respecte .gitignore — résultats propres
$ rg "import React" mon-projet/
# Seuls les fichiers sources pertinents
# Forcer rg à ignorer le .gitignore
$ rg --no-ignore "import React" mon-projet/
Filtrage par type de fichier
# Chercher uniquement dans les fichiers Python
$ rg "def process" -t py
# Chercher partout sauf dans les fichiers JSON
$ rg "config" -g '!*.json'
# grep équivalent
$ grep -rn --include='*.py' "def process" .
$ grep -rn --exclude='*.json' "config" .
Contexte et multiline
# 3 lignes avant et après le match
$ rg -C3 "error" -t log /var/log/
# Multiline : chercher un pattern sur plusieurs lignes
$ rg -U "class\n\s+def" -t py .
# grep équivalent : grep -Pz "class\n\s+def"
Format de sortie JSON
# Sortie JSON pour scripting
$ rg --json "TODO" src/ | head -20
{"type":"begin","data":{"path":{"text":"src/main.rs"}}}
{"type":"match","data":{"path":{"text":"src/main.rs"},"lines":{"text":"// TODO: refactor this\n"},"line_number":42,"absolute_offset":1234,"submatches":[{"match":{"text":"TODO"},"start":3,"end":7}]}}
{"type":"end","data":{"path":{"text":"src/main.rs"},"binary_offset":null,"stats":{"elapsed":{"secs":0,"nanos":234567},"searches":1,"searches_with_match":1,"bytes_searched":45321,"bytes_printed":128,"matched_lines":1,"matches":1}}}
Quand utiliser grep
🖥️ Scripts universels
grep est garanti sur tout système POSIX. Pour les scripts de monitoring, les crons, les Dockerfiles minimalistes (Alpine, BusyBox) : pas de dépendance supplémentaire.
🔧 Pipelines système
journalctl | grep error, dmesg | grep oom, ps aux | grep nginx. Pour le filtrage de flux en temps réel, grep reste le plus simple.
🐳 Conteneurs légers
Dans un Dockerfile Alpine de 5 Mo, grep est présent. ripgrep pèse ~5 Mo de plus — pas négligeable pour les images de production.
📄 PCRE avancé
Backreferences, lookaheads, lookbehinds : grep -P (PCRE) supporte tout. ripgrep nécessite --pcre2 compilé.
Quand utiliser ripgrep
⚡ Dev au quotidien
Chercher dans un gros monorepo, un projet node_modules, un kernel : ripgrep est 10-40× plus rapide. Gain de temps mesurable chaque jour.
🔍 Code review & audit
Trouver toutes les occurrences d'une fonction, un TODO, une clé hardcodée : le filtrage par type (-t py) et le format JSON simplifient les scripts d'audit.
🗂️ Projets avec .gitignore
Pas besoin d'exclure manuellement node_modules, vendor, build. rg le fait automatiquement. Moins de bruit, résultats plus pertinents.
🤖 Scripting avancé
Sortie JSON (--json), stats détaillées (--stats), remplacement (--replace) : ripgrep offre des capacités de scripting supérieures à grep.
Pattern fallback : grep/rg interchangeable
Pour les scripts destinés à tourner sur des environnements hétérogènes, un pattern simple de fallback est recommandé :
#!/bin/bash
# Fallback pattern : rg si disponible, sinon grep
SEARCHER=""
if command -v rg &>/dev/null; then
SEARCHER="rg"
else
SEARCHER="grep -rn"
fi
# Utilisation
$SEARCHER "$1" "${2:-.}"
✅ Checklist — Script portable
✓ Détecter rg avec command -v
✓ Fallback vers grep -rn (le -n matche le comportement par défaut de rg)
✓ Ne pas utiliser les flags spécifiques à rg (-t, -g) dans le fallback
✓ Tester le script dans un conteneur Alpine sans ripgrep
✓ Documenter la dépendance optionnelle dans le README
Pièges courants
⚠️ Piège n°1 — rg ignore les fichiers cachés par défaut
rg "pattern" ne cherche pas dans les fichiers/dossiers commençant par . (dotfiles, .env, .bashrc). Solution : rg --hidden "pattern" ou rg ".+" --hidden.
⚠️ Piège n°2 — Sensibilité à la casse différente
grep est sensible à la casse par défaut. ripgrep est aussi sensible par défaut, mais les alias courants de rg incluent --smart-case. Résultat : un même pattern peut matcher différemment selon l'alias configuré.
⚠️ Piège n°3 — Sortie binaire tronquée
grep affiche Binary file foo matches sans montrer le contenu. rg affiche les lignes matchées même dans les binaires (avec --binary). Ce comportement asymétrique peut surprendre lors de la migration.
⚠️ Piège n°4 — Pas d'équivalent exact pour grep -P
Les lookaheads/lookbehinds de PCRE ne sont pas supportés par le moteur regex par défaut de rg. Il faut rg --pcre2, qui n'est pas toujours compilé. Vérifier avec rg --pcre2-version.
FAQ
Conclusion
Le comparatif grep vs ripgrep n'est pas un match à somme nulle. Les deux outils excellent dans leur domaine :
- grep pour l'universalité, les pipelines, les conteneurs légers et les regex avancées (PCRE).
- ripgrep pour la vitesse brute, le dev au quotidien, et la recherche intelligente dans les gros codebases.
Le bon choix dépend du contexte. En production et dans les scripts portables : grep. Sur ta workstation, dans ton IDE, sur un monorepo : ripgrep. Et pour les scripts partagés, le pattern fallback te donne le meilleur des deux mondes.
Besoin d'optimiser ton infrastructure Linux ou d'automatiser tes opérations ?
Linux-Man accompagne les TPE et PME en hébergement, infogérance et conseil DevOps.
Sources : man grep · GNU grep manual · ripgrep GitHub · ripgrep User Guide