<!--
  canonical-url: https://www.avonture.be/fr/blog/ripgrep
  published:     2026-07-06
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# ripgrep — l'outil de recherche qui a changé mon workflow WSL2

> Découvrez ripgrep, l'alternative ultra-rapide à grep écrite en Rust. Installation sur Ubuntu/WSL2, configuration ZSH, fonctions shell pratiques et cas d'usage réels qui vont transformer votre façon de chercher dans le code au quotidien.

---
![ripgrep — l'outil de recherche qui a changé mon workflow WSL2](/img/v2/ripgrep.webp)

**TL;DR**

ripgrep (`rg`) est un outil de recherche ligne par ligne écrit en Rust qui surpasse largement le grep traditionnel — surtout sur les gros codebases. Il respecte `.gitignore` par défaut, ignore les fichiers binaires et gère l'Unicode nativement. Cet article couvre l'installation sur Ubuntu/WSL2, un fichier de configuration `~/.ripgreprc`, des alias et fonctions ZSH pour votre `~/.zshrc` et votre répertoire `~/.zsh/fns/`, ainsi que des cas d'usage réels qui vous feront vous demander comment vous avez fait sans lui jusqu'ici.

Zut. J'ai tapé cette commande tellement de fois que je pourrais la taper les yeux fermés : `grep -rn --include="*.php" "getUser" . | grep -v vendor`. Ça marche — grep est un classique, il fait le job. Mais au fil des années, j'ai accumulé tellement de flags, tellement d'alias, tellement de contournements devenus automatiques pour les bizarreries de grep... À un moment, il faut se poser la question : est-ce qu'il existe mieux ?

> **Que fait réellement cette commande ?:**
>
> `grep -rn --include="*.php" "getUser" .` se décompose comme suit : `-r` cherche récursivement dans tous les sous-répertoires, `-n` affiche le numéro de ligne de chaque correspondance, `--include="*.php"` limite la recherche aux seuls fichiers `.php`, `"getUser"` est le motif recherché et `.` indique de partir du répertoire courant. Le `| grep -v vendor` final envoie les résultats dans un second grep qui filtre et EXCLUT (`-v`) toute ligne contenant `vendor` — un contournement courant pour exclure le dossier de dépendances `vendor/`, que grep n'a aucun moyen natif d'ignorer.

Oui, il existe mieux. Ça s'appelle [ripgrep](https://github.com/BurntSushi/ripgrep), et une fois qu'on y a goûté, impossible de revenir en arrière.

*Il appartient à la même famille de réécritures modernes que [eza](/blog/linux-eza) (pour `ls`) et [delta](/blog/git-delta) (pour `git diff`).*

## ripgrep vs grep — comparaison côte à côte {#ripgrep-vs-grep--a-side-by-side-look}

Laissez-moi vous montrer pourquoi ripgrep s'impose aussi vite. Voici les mêmes recherches exprimées dans les deux outils :

**Avec grep :**

```bash
grep -rn --include="*.php" "getUser" . \
  | grep -v vendor
```

**Avec ripgrep :**

```bash
rg "getUser" --type php
```

**Avec grep :**

```bash
grep -rn -i "TODO" . \
  --include="*.py" \
  --include="*.pyi" \
  --exclude-dir=.venv \
  --exclude-dir=dist
```

**Avec ripgrep :**

```bash
rg -i "TODO" --type py
```

**Avec grep :**

```bash
grep -rn "DB_PASSWORD" . \
  --include="*.env" \
  --include="*.yml" \
  --include="*.yaml"
```

**Avec ripgrep :**

```bash
rg "DB_PASSWORD" -t yaml -t sh
```

Bien sûr, les flags de grep sont puissants une fois qu'on les connaît par cœur. Mais la syntaxe de ripgrep est tout simplement plus propre — et par défaut, il ignore déjà `vendor/`, `node_modules/` et tout ce qui se trouve dans votre `.gitignore`, sans le moindre flag supplémentaire.

## Qu'est-ce que ripgrep ? {#what-is-ripgrep}

ripgrep (`rg` en ligne de commande) est un outil de recherche ligne par ligne écrit en Rust par Andrew Gallant (BurntSushi). La vitesse est son argument phare — les benchmarks montrent systématiquement qu'il devance grep, ag (le Silver Searcher) et ack de loin sur les gros codebases — et [hyperfine](/blog/hyperfine) vous permet de vérifier cette affirmation sur votre propre machine. Mais la vitesse brute n'est qu'une partie de l'histoire.

Ce qui rend ripgrep réellement meilleur au quotidien, ce sont ses **valeurs par défaut intelligentes** :

* Il respecte automatiquement les fichiers `.gitignore`, `.ignore` et `.rgignore` — donc `vendor/`, `node_modules/`, `dist/` et `.git/` sont ignorés sans aucune gymnastique à base de `--exclude-dir`.
* Il ignore les fichiers binaires par défaut.
* Il colorise et regroupe la sortie par nom de fichier d'office.
* Il utilise l'Unicode par défaut — fini la sortie illisible sur les noms de fichiers ou les contenus accentués.
* Il supporte la syntaxe regex moderne, y compris PCRE2 avec le flag `-P`.
* Il ne cherche dans les fichiers cachés que si vous le demandez explicitement (`--hidden`).

Ce dernier comportement d'affichage est sous-estimé. Des résultats lisibles, groupés, colorisés — immédiatement, sans la moindre configuration. Plutôt sympa, non ?

## Le voir à l'œuvre avec Docker {#seeing-it-in-action-with-docker}

Avant de toucher à votre propre `~/.zshrc`, essayez ripgrep dans un container jetable qui embarque déjà
la config `~/.ripgreprc`, les fonctions `rgtodo`/`rgenv` et un petit faux projet conçu
pour mettre en valeur les valeurs par défaut intelligentes : un dossier `vendor/` qui doit rester invisible, des commentaires TODO/FIXME,
un `DB_PASSWORD` qui fuit et un appel `console.log(token)` qui mérite d'être signalé.

> **Pourquoi commencer par Docker ?:**
>
> Le Dockerfile ci-dessous reproduit exactement le `.ripgreprc`, les fonctions `.zsh/fns/` et la section `.zshrc`
> de cet article, puis construit le projet de démonstration. Rien ne change sur votre propre machine.

**Dockerfile**

```docker
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        zsh \
        ripgrep \
        git \
        ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# ~/.ripgreprc — the exact config file from this article
RUN printf '%s\n' \
    '--colors=match:fg:red' \
    '--colors=match:style:bold' \
    '--colors=path:fg:blue' \
    '--follow' \
    '--glob=!.cache/*' \
    '--glob=!.git/*' \
    '--glob=!.output/*' \
    '--glob=!.yarn/*' \
    '--glob=!build/*' \
    '--glob=!dist/*' \
    '--glob=!node_modules/*' \
    '--glob=!vendor/*' \
    '--hidden' \
    '--max-filesize=10M' \
    '--smart-case' \
    > /root/.ripgreprc

# ~/.zsh/fns/ — the two custom functions from this article
RUN mkdir -p /root/.zsh/fns

RUN printf '%s\n' \
    '# rgtodo — surface all TODO/FIXME/HACK/NOTE comments in the project' \
    'rgtodo() {' \
    '    local dir="${1:-.}"' \
    '    rg --color=always --line-number --smart-case "(TODO|FIXME|HACK|NOTE):?\s" "${dir}" | sort' \
    '}' \
    > /root/.zsh/fns/rgtodo.zsh

RUN printf '%s\n' \
    '# rgenv — find all references to an environment variable' \
    'rgenv() {' \
    '    local var="${1}"' \
    '    [[ -z "${var}" ]] && { echo "Usage: rgenv <VARIABLE_NAME>"; return 1; }' \
    "    rg --type-add 'config:*.{env,cfg,ini,conf}' --type config --type yaml --type sh --type php --type py \"\${var}\"" \
    '}' \
    > /root/.zsh/fns/rgenv.zsh

# ~/.zshrc — the exact ripgrep section from this article
RUN printf '%s\n' \
    'export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"' \
    'for fn_file in ~/.zsh/fns/*.zsh; do source "${fn_file}"; done' \
    'alias rgp="rg --type php"' \
    'alias rgj="rg --type js"' \
    'alias rgy="rg --type yaml"' \
    'alias rgd="rg --glob \"Dockerfile*\" --glob \"*.dockerfile\""' \
    >> /root/.zshrc

# Build a small demo project: a `vendor/` folder that must stay invisible, a
# PHP controller worth finding, TODO/FIXME comments, a leaking JWT in a JS
# file, and a compose file with image references
RUN mkdir -p /root/demo/vendor/legacy /root/demo/src && \
    printf '<?php\nfunction getUser($id) {\n    // vendored copy, must NOT show up in searches\n}\n' \
        > /root/demo/vendor/legacy/User.php && \
    printf '<?php\nfunction getUser($id) {\n    return User::find($id);\n}\n' \
        > /root/demo/src/UserController.php && \
    printf '<?php\n// TODO: cache this lookup\n// FIXME: N+1 query below\nfunction getAllUsers() {\n    // HACK: temporary workaround for #482\n}\n' \
        > /root/demo/src/legacy.php && \
    printf 'DB_PASSWORD=demo-secret\n' > /root/demo/.env && \
    printf 'services:\n  app:\n    image: php:8.3-fpm\n  db:\n    image: postgres:16\n' \
        > /root/demo/compose.yml && \
    printf 'function refreshToken(token) {\n  console.log(token);\n}\n\nfunction checkout(cart) {\n  for (const item of cart) {\n    console.log(item);\n  }\n}\n' \
        > /root/demo/src/app.js && \
    printf 'FROM php:8.3-fpm\nCOPY . /app\n' > /root/demo/Dockerfile.app && \
    printf 'vendor/\n' > /root/demo/.gitignore && \
    git -C /root/demo init -q && \
    git -C /root/demo -c user.email=demo@example.com -c user.name=Demo \
        add -A && \
    git -C /root/demo -c user.email=demo@example.com -c user.name=Demo \
        commit -q -m "Demo project"

WORKDIR /root/demo

# Signal clearly that this shell runs inside a container
RUN echo "PROMPT='%B%F{yellow}🐳 %F{cyan}%n%f%b %~ %# '" >> /root/.zshrc

CMD ["/bin/zsh", "-i", "-l"]
```

Buildez et lancez :

```bash
$ docker build -t ripgrep-demo .
[+] Building 21.3s (10/10) FINISHED
✔ exporting to image
$ docker run --rm -it ripgrep-demo
🐳 root ~/demo #
```

Jouez maintenant avec les scénarios décrits plus haut, en direct :

```bash
$ rg "getUser"
src/UserController.php
2:function getUser($id) {

src/legacy.php
4:function getAllUsers() {

$ rgtodo
src/legacy.php:2:// TODO: cache this lookup
src/legacy.php:3:// FIXME: N+1 query below

$ rgenv DB_PASSWORD
.env
1:DB_PASSWORD=demo-secret

$ rg -C 2 "console.log"
src/app.js
2-function refreshToken(token) {
3:  console.log(token);
4-}
7-  for (const item of cart) {
8:    console.log(item);
9-  }
```

Remarquez que `vendor/legacy/User.php` — qui définit lui aussi `getUser`, exprès — n'apparaît jamais dans
aucune de ces recherches : le `.gitignore` et l'entrée de configuration `--glob=!vendor/*` l'excluent tous les deux,
exactement comme décrit plus haut. Essayez `rg --no-ignore "getUser"` pour le voir réapparaître.

## Installation sur Ubuntu / WSL2 {#installation-on-ubuntu--wsl2}

ripgrep est présent dans les dépôts de paquets par défaut d'Ubuntu, donc l'installer tient en une ligne :

Prerequisite: ripgrep

```bash
$ sudo apt update && sudo apt install ripgrep -y

Reading package lists... Done
Building dependency tree... Done
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
```

Verify:

```bash
$ rg --version

ripgrep 14.1.0
-rev 0 (rev 4649aa9700 2024-03-30)
features: +SIMD +AVX (compiled), +SIMD +AVX (runtime)
```

> **Vous voulez la dernière version ?:**
>
> Les dépôts Ubuntu ont parfois quelques releases de retard sur ripgrep en amont. Pour la version la plus récente, récupérez le dernier package `.deb` directement depuis la [page des releases GitHub](https://github.com/BurntSushi/ripgrep/releases) et installez-le avec `sudo dpkg -i ripgrep_*.deb`. À partir de la version 14, vous bénéficiez aussi d'un meilleur support de PCRE2 et d'un parcours de répertoires plus rapide.

## Configuration — \~/.ripgreprc {#configuration--ripgreprc}

Comme la plupart des outils Unix, ripgrep se configure via un fichier dédié. Vous le désignez avec la variable d'environnement `RIPGREP_CONFIG_PATH`. Voici un exemple de fichier `~/.ripgreprc` :

**\~/.ripgreprc**

```
--colors=match:fg:red
--colors=match:style:bold
--colors=path:fg:blue
--follow
--glob=!.cache/*
--glob=!.git/*
--glob=!.output/*
--glob=!.yarn/*
--glob=!build/*
--glob=!dist/*
--glob=!node_modules/*
--glob=!vendor/*
--hidden
--max-filesize=10M
--smart-case
```

Chaque ligne est un flag appliqué par défaut à chaque invocation de `rg`. Quelques points méritent une explication :

* `--hidden` fait chercher ripgrep à l'intérieur des fichiers et dossiers cachés (tout ce qui commence par un point). Combiné à l'exclusion `--glob=!.git/*`, cela veut dire que vous pouvez chercher dans les fichiers `.env`, `.zshrc`, `.gitignore` et consorts sans ouvrir toute la plomberie interne de `.git/`.
* `--max-filesize=10M` ignore silencieusement les très gros fichiers (dumps de logs, assets générés) qui noieraient sinon vos résultats.
* `--smart-case` est probablement le réglage le plus impactant : les recherches sont insensibles à la casse par défaut, mais dès que votre motif contient une majuscule, ripgrep bascule en correspondance exacte de casse — exactement le comportement que je veux 95 % du temps.

## Configuration du shell — \~/.zshrc ou \~/.bashrc {#shell-setup--zshrc-or-bashrc}

Une fois le fichier de config en place, j'ajoute la variable d'environnement, le chargeur de fonctions et une poignée d'alias par type de fichier dans le fichier rc de mon shell. Le contenu est identique pour zsh et bash, sauf la boucle de chargement :

**\~/.zshrc (ripgrep section)**

```bash
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"

# If you don't already have such loop...
# Load custom ZSH functions from ~/.zsh/fns/
for fn_file in ~/.zsh/fns/*.zsh; do
    source "${fn_file}"
done

# Type-specific shortcuts
alias rgp='rg --type php'
alias rgj='rg --type js'
alias rgt='rg --type ts'
alias rgm='rg --type md'
alias rgy='rg --type yaml'
alias rgb='rg --type sh'
alias rgd='rg --glob "Dockerfile*" --glob "*.dockerfile"'
```

**\~/.bashrc (ripgrep section)**

```bash
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"

# If you don't already have such loop...
# Load custom bash functions from ~/.bash/fns/
for fn_file in ~/.bash/fns/*.sh; do
    [[ -r "${fn_file}" ]] && source "${fn_file}"
done

# Type-specific shortcuts
alias rgp='rg --type php'
alias rgj='rg --type js'
alias rgt='rg --type ts'
alias rgm='rg --type md'
alias rgy='rg --type yaml'
alias rgb='rg --type sh'
alias rgd='rg --glob "Dockerfile*" --glob "*.dockerfile"'
```

Le test `-r` évite qu'un dossier `~/.bash/fns/` vide n'affiche une erreur à chaque démarrage du shell.

La boucle `for fn_file` source automatiquement chaque fichier de fonction présent dans ce répertoire — ajouter une nouvelle fonction revient donc simplement à y déposer un nouveau fichier, sans avoir à retoucher votre fichier rc.

Les alias par type (`rgp` pour PHP, `rgt` pour TypeScript, `rgm` pour Markdown, etc.) font gagner des frappes quand vous savez exactement dans quel type de fichier vous cherchez. J'utilise `rgp "getUser"` ou `rgm "## Installation"` des dizaines de fois par jour.

## Fonctions shell — \~/.zsh/fns/ ou \~/.bash/fns/ {#shell-functions--zshfns-or-bashfns}

C'est ici que ça devient amusant. Voici trois fonctions que j'ai installées dans mon répertoire `~/.zsh/fns/`, chacune résolvant un vrai problème.

### rgf — recherche interactive avec fzf {#rgf--interactive-search-with-fzf}

J'ai détaillé cette combinaison dans un article dédié : [FZF + ripgrep: Interactive Code Search with Live Preview](/blog/fzf-ripgrep). En résumé : envoyez `rg` dans `fzf` avec un panneau de prévisualisation `bat` et vous obtenez un chercheur flou interactif qui cherche dans le *contenu* des fichiers, prévisualise les correspondances avec coloration syntaxique et ouvre votre éditeur exactement à la ligne trouvée. Si vous n'avez pas encore lu cet article, le détour en vaut la peine.

### rgtodo — faire remonter toute la dette technique d'un coup {#rgtodo--surface-all-technical-debt-at-once}

Chaque codebase en est truffé dans ses commentaires : `TODO`, `FIXME`, `HACK`, `NOTE`, `XXX`. Cette fonction les fait tous remonter à la surface :

**rgtodo.sh**

```bash
# rgtodo — surface all TODO/FIXME/HACK/NOTE comments in the project
rgtodo() {
    local dir="${1:-.}"

    rg \
        --color=always \
        --line-number \
        --smart-case \
        '(TODO|FIXME|HACK|NOTE):?\s' \
        "${dir}" \
        | sort
}
```

Lancez `rgtodo` à la racine de n'importe quel projet et vous obtenez une liste triée et colorisée de chaque marqueur de commentaire. Lancez `rgtodo src/` pour la restreindre à un dossier précis. Révélateur sur des codebases qui ont quelques années au compteur.

```bash
$ rgtodo src/

src/Api/UserController.php:47:    // TODO: replace with a proper permission check
src/Api/UserController.php:112:   // FIXME: this bypasses rate limiting on retry
src/Services/MailService.php:23:  // HACK: temporary workaround for #4521
```

### rgenv — traquer l'usage des variables d'environnement {#rgenv--track-down-environment-variable-usage}

Dans les projets très orientés Docker, les variables d'environnement finissent éparpillées entre des fichiers `.env`, `compose.yml`, des bootstraps PHP et des configs Python. Cette fonction cherche dans tous ces fichiers d'un seul coup :

**rgenv.sh**

```bash
# rgenv — find all references to an environment variable across config and source files
rgenv() {
    local var="${1}"

    if [[ -z "${var}" ]]; then
        echo "Usage: rgenv <VARIABLE_NAME>"
        return 1
    fi

    rg \
        --type-add 'config:*.{env,cfg,ini,conf}' \
        --type config \
        --type yaml \
        --type sh \
        --type php \
        --type py \
        "${var}"
}
```

`rgenv DB_PASSWORD` montre instantanément chaque fichier qui référence cette variable — qu'il la définisse, la consomme ou la passe comme secret Docker. Inestimable pour déboguer les dérives de configuration dans les setups multi-containers complexes.

```bash
$ rgenv DB_PASSWORD

.env:3:DB_PASSWORD=supersecret
compose.yml:18:      - DB_PASSWORD=${DB_PASSWORD}
src/Config/database.php:14:    'password' => env('DB_PASSWORD'),
```

### Installer rgtodo et rgenv {#installing-rgtodo-and-rgenv}

Les deux fonctions sont du code shell pur : les mêmes fichiers fonctionnent en zsh et en bash, seul le dossier change. La boucle de chargement est déjà dans votre fichier rc depuis la section précédente.

**1. Créez les fichiers** dans `~/.zsh/fns/` :

**Project: \~/.zsh/fns**

**rgtodo.zsh**

```bash
# rgtodo — surface all TODO/FIXME/HACK/NOTE comments in the project
rgtodo() {
    local dir="${1:-.}"

    rg \
        --color=always \
        --line-number \
        --smart-case \
        '(TODO|FIXME|HACK|NOTE):?\s' \
        "${dir}" \
        | sort
}
```

**rgenv.zsh**

```bash
# rgenv — find all references to an environment variable across config and source files
rgenv() {
    local var="${1}"

    if [[ -z "${var}" ]]; then
        echo "Usage: rgenv <VARIABLE_NAME>"
        return 1
    fi

    rg \
        --type-add 'config:*.{env,cfg,ini,conf}' \
        --type config \
        --type yaml \
        --type sh \
        --type php \
        --type py \
        "${var}"
}
```

**2. Ouvrez un nouveau terminal** (ou lancez `exec zsh`).

**1. Créez les fichiers** dans `~/.bash/fns/` :

**Project: \~/.bash/fns**

**rgtodo.sh**

```bash
# rgtodo — surface all TODO/FIXME/HACK/NOTE comments in the project
rgtodo() {
    local dir="${1:-.}"

    rg \
        --color=always \
        --line-number \
        --smart-case \
        '(TODO|FIXME|HACK|NOTE):?\s' \
        "${dir}" \
        | sort
}
```

**rgenv.sh**

```bash
# rgenv — find all references to an environment variable across config and source files
rgenv() {
    local var="${1}"

    if [[ -z "${var}" ]]; then
        echo "Usage: rgenv <VARIABLE_NAME>"
        return 1
    fi

    rg \
        --type-add 'config:*.{env,cfg,ini,conf}' \
        --type config \
        --type yaml \
        --type sh \
        --type php \
        --type py \
        "${var}"
}
```

**2. Ouvrez un nouveau terminal** (ou lancez `exec bash`).

Vérifiez que le shell les connaît : `type rgtodo rgenv` doit répondre deux fois `… is a shell function`.

## Cas d'usage réels {#real-world-use-cases}

Passons en revue les recherches que je lance le plus souvent dans mon workflow WSL2 quotidien.

### Trouver la définition d'une fonction dans un projet PHP {#finding-a-function-definition-across-a-php-project}

```bash
rg "function getUser" --type php
```

Sans ripgrep : il faut ajouter `--include="*.php"`, `--exclude-dir=vendor`, `-rn`. Avec ripgrep : tapez-le, point. Le répertoire `vendor/` est déjà exclu parce qu'il est dans le `.gitignore`.

### Chercher une référence d'image dans tous les fichiers Docker Compose {#searching-all-docker-compose-files-for-an-image-reference}

```bash
rgy "image:"
```

C'est notre alias `rgy` (`rg --type yaml`). Pratique pour auditer un repository à la recherche de références d'images obsolètes, ou pour trouver tous les services qui partagent une image de base.

### Lignes de contexte — comprendre le code autour d'une correspondance {#context-lines--understanding-code-around-a-match}

Le flag `-C N` affiche N lignes de contexte autour de chaque correspondance — une fonctionnalité que j'utilise en permanence :

```bash
$ rg "DB_HOST" -C 3 --type php

src/Config/Database.php
15-  'driver'   => 'mysql',
16:  'host'     => env('DB_HOST', '127.0.0.1'),
17-  'database' => env('DB_DATABASE', 'forge'),
18-  'username' => env('DB_USERNAME', 'forge'),
19-  'password' => env('DB_PASSWORD', ''),
```

Vous pouvez aussi utiliser `-A N` (après) et `-B N` (avant) séparément, exactement comme avec grep.

Un scénario plus courant : un collègue laisse des appels `console.log()` dans du JavaScript avant de pousser en production. Sans contexte, vous ne voyez que la ligne elle-même — vous savez qu'elle existe, mais pas à quel point c'est grave. Avec `-C 2` :

```bash
$ rg "console\.log" -C 2 --type js

src/auth/login.js
40-  const authToken = generateToken(user)
41-  const refreshToken = generateRefresh(user)
42:  console.log("token:", authToken)
43-  return { authToken, refreshToken }

src/payment/checkout.js
85-  for (const item of cartItems) {
86-    const price = calculatePrice(item)
87:    console.log("debug")
88-    total += price
```

Là, vous pouvez faire la différence. La première correspondance logue un token JWT en clair — c'est un problème de sécurité, pas juste du bruit. La seconde se trouve dans une boucle `for` sur un panier : un seul passage en caisse inonderait la console de centaines de lignes. Le contexte transforme une liste de correspondances en information exploitable.

### Compter les occurrences par fichier {#counting-occurrences-per-file}

```bash
rg -c "console.log" --type js
```

Ceci affiche le nombre de correspondances par fichier — parfait pour identifier quels fichiers sources contiennent encore des instructions de debug avant une release.

### Renommage en masse avec rg + sed {#bulk-rename-with-rg--sed}

ripgrep est volontairement en lecture seule (pas de mode `-i` d'édition sur place), mais il se marie très bien avec `sed` pour du refactoring en masse :

```bash
$ rg -l "oldFunctionName" --type php | xargs sed -i 's/oldFunctionName/newFunctionName/g'
```

`rg -l` ne liste que les noms de fichiers qui contiennent des correspondances. L'envoyer dans `xargs sed -i` réécrit exactement ces fichiers — ni plus, ni moins. Bien plus sûr qu'un `find | xargs sed` brut qui n'a aucune idée des fichiers réellement concernés.

### Chercher dans plusieurs types de fichiers à la fois {#searching-multiple-file-types-at-once}

```bash
rg "API_KEY" -t php -t yaml -t sh
```

Plusieurs flags `-t` se combinent — ripgrep cherche dans tous les types correspondants en une seule passe, avec une sortie colorisée unifiée.

### Limiter la profondeur de recherche {#limiting-search-depth}

```bash
rg "FROM" --glob "Dockerfile*" --max-depth 3
```

`--max-depth` est idéal quand vous voulez rester près du répertoire courant sans plonger dans chaque sous-répertoire imbriqué.

## À retenir {#key-takeaways}

**ripgrep : aide-mémoire**

* **Installer** — `sudo apt install ripgrep` sur Ubuntu/WSL2

* **Configurer** — créez `~/.ripgreprc` et pointez dessus via `RIPGREP_CONFIG_PATH` dans `~/.zshrc`

* **Flags de type** — `-t php` au lieu de `--include="*.php"` — plus court et plus malin

* **Smart case** — `--smart-case` vous donne des recherches insensibles à la casse qui basculent en exact dès que vous utilisez une majuscule

* **Conscient du gitignore** — `vendor/`, `node_modules/`, `.git/` sont exclus automatiquement ; aucun flag nécessaire

* **Lignes de contexte** — `-C 3` affiche 3 lignes au-dessus et en dessous de chaque correspondance

* **Mode liste de fichiers** — `rg -l` ne renvoie que les noms de fichiers ; envoyez-les dans `xargs` pour des opérations en masse

* **Mode interactif** — `rgf "pattern"` combine ripgrep et fzf pour une recherche avec prévisualisation en direct ; configuration complète dans [FZF + ripgrep](/blog/fzf-ripgrep)

## Conclusion {#conclusion}

Au début de cet article, je disais avoir tapé cette commande `grep -rn --include="*.php" ... | grep -v vendor` tellement de fois qu'elle était devenue un réflexe. Aujourd'hui, chaque fois que j'ouvre un terminal dans WSL2, je tape `rg` sans même y penser. L'exclusion de `vendor/` est automatique, la sortie est lisible sans aucun flag et la recherche est réellement plus rapide sur les gros codebases. Entre la configuration `~/.ripgreprc`, les alias de type dans `~/.zshrc`, des fonctions comme `rgtodo` et `rgenv` dans `~/.zsh/fns/`, et la recherche interactive `rgf` couverte dans [un article dédié](/blog/fzf-ripgrep), ripgrep a cessé d'être un outil que je choisis consciemment pour devenir la colonne vertébrale invisible de ma façon de naviguer dans le code au quotidien. Si vous en êtes encore à grep nu dans votre environnement WSL2, accordez-vous vingt minutes avec ripgrep — c'est tout ce qu'il faut.
