<!--
  canonical-url: https://www.avonture.be/fr/blog/atuin-bash-history
  published:     2026-09-14
  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.
-->

# Atuin — Boostez votre historique shell avec une base de données consultable et horodatée

> Fatigué de perdre vos commandes dans le labyrinthe du CTRL+R par défaut ? Atuin remplace l'historique de votre shell par une TUI complète adossée à SQLite — horodatage, contexte, synchronisation multi-machines, et une comparaison claire avec la recherche d'historique basée sur FZF.

---
![Atuin — Boostez votre historique shell](/img/v2/atuin.webp)

**TL;DR**

L'historique shell par défaut est un cimetière de commandes que vous ne retrouverez jamais — pas d'horodatage, pas de contexte, 500 lignes et puis plus rien. Atuin le remplace par une TUI adossée à SQLite qui enregistre chaque commande avec son code de sortie, son répertoire de travail, sa durée et son horodatage. Vous obtenez un `CTRL`+`R` instantanément amélioré, avec filtrage par host ou par dossier, sans sacrifier votre historique existant. La seconde moitié de cet article détaille l'installation sur Bash et ZSH, et se termine par une comparaison en face à face avec l'approche classique FZF+history.

Zut, ça recommence. J'ai tapé `CTRL`+`R`, cherché cette longue commande `docker run` que j'avais construite il y a trois semaines, et rien — ou pire, la mauvaise version de mardi dernier. L'historique bash par défaut est juste... insuffisant. Cinq cents lignes, pas d'horodatage, aucun contexte sur le dossier où vous étiez ni même sur le succès de la commande.

[J'ai déjà écrit sur les astuces d'historique intégrées](/blog/linux-history) — `HISTSIZE`, `HISTTIMEFORMAT`, `fc`, la recherche inversée — et ça aide, oui. Mais ce sont des contournements, pas une solution. Vous cherchez toujours dans un fichier texte plat sans aucune donnée structurée.

Atuin change complètement la donne.

**Quick Jump:** [Le voir en action](#seeing-it-in-action-with-docker) | [L'installer pour de vrai](#installing-atuin) | [Atuin vs. FZF](#atuin-vs-fzf-history)

## Qu'est-ce qu'Atuin ? {#what-is-atuin}

[Atuin](https://github.com/atuinsh/atuin) (le nom est un clin d'œil à la tortue-monde de Terry Pratchett) remplace l'historique de votre shell. Au lieu d'ajouter les commandes à `~/.bash_history`, il écrit chaque commande dans une base SQLite locale avec des métadonnées riches :

* **Horodatage** — quand l'avez-vous lancée ?
* **Durée** — combien de temps a-t-elle pris ?
* **Code de sortie** — a-t-elle réussi ?
* **Répertoire de travail** — où étiez-vous ?
* **Nom d'host** — sur quelle machine ?

Quand vous appuyez sur `CTRL`+`R`, au lieu du minuscule prompt de recherche inversée incrémentale, Atuin ouvre une TUI plein écran où vous pouvez taper, filtrer par host ou par répertoire, et naviguer aux flèches. Ça fonctionne sur Bash, ZSH, Fish et Nushell. Une synchronisation cloud chiffrée de bout en bout, optionnelle, permet de partager l'historique entre machines — mais c'est entièrement facultatif ; Atuin fonctionne parfaitement hors ligne et en local.

> **Aucun cloud requis:**
>
> La synchronisation d'Atuin est optionnelle. Si vous ne lancez jamais `atuin register` ni `atuin login`, votre historique reste 100 % local dans `~/.local/share/atuin/history.db`. Cet article ne traite que de l'expérience locale.

## Le voir en action avec Docker {#seeing-it-in-action-with-docker}

*Vous connaissez déjà Atuin, ou vous voulez juste l'avoir sur votre machine ? [Passez directement à l'installation](#installing-atuin) — ce chapitre n'est qu'un container jetable pour l'essayer sans risque.*

Vous me connaissez bien maintenant — j'aime tout mettre en container. Avant d'installer quoi que ce soit sur votre machine, montons un container jetable pour que vous sentiez ce qu'Atuin donne en pratique.

> **Pourquoi Docker d'abord ?:**
>
> Un container Docker vous permet de tester Atuin sans toucher à la configuration réelle de votre shell. Si ça ne vous plaît pas, vous supprimez le container. Aucun hook résiduel dans votre `~/.bashrc`.

Deux fichiers dans un dossier — et tous les deux sont de l'**échafaudage de démo, rien d'autre**. `seed-history.sh` en particulier ne fait pas partie de l'usage d'Atuin : son seul rôle est de fabriquer un historique plausible pour que l'écran suivant ait quelque chose à montrer. Aucun de ces deux fichiers n'a sa place sur votre propre machine, où [installer Atuin](#installing-atuin) se résume à un `brew install`.

**Project: /tmp/atuin-demo**

> **Note:**
>
> Construisez l'image et démarrez le container : `docker build -t atuin-demo . && docker run --rm -it atuin-demo`

**Dockerfile**

```docker
FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        bash \
        bash-completion \
        ca-certificates \
        curl \
        sqlite3 \
        tar && \
    rm -rf /var/lib/apt/lists/*

# Install Atuin
RUN curl -fsSL \
    https://github.com/atuinsh/atuin/releases/download/v18.22.0/atuin-x86_64-unknown-linux-musl.tar.gz \
    | tar -xz && \
    mv atuin-*/atuin /usr/local/bin/

# Install bash-preexec (hook system required by Atuin on Bash)
RUN curl -fsSL \
    https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh \
    -o /opt/bash-preexec.sh

# Pre-populate the database so CTRL+R has a real history to search from the
# very first second. Demo-only: on a real machine Atuin fills this by itself.
COPY seed-history.sh /opt/seed-history.sh
RUN chmod +x /opt/seed-history.sh

# Wire Atuin into the interactive shell. The seeding script runs last and is
# idempotent: it does nothing if the database already holds commands.
RUN printf '%s\n' \
    'source /opt/bash-preexec.sh' \
    'eval "$(atuin init bash)"' \
    '/opt/seed-history.sh' \
    >> /root/.bashrc

CMD ["/bin/bash", "-i"]
```

**seed-history.sh**

```bash
#!/usr/bin/env bash
#
# Seed the local Atuin database with a realistic shell history, so that pressing
# CTRL+R in a freshly started demo container shows something worth searching.
#
# This is a DEMO device, not something you would ever run on a real machine: there,
# Atuin records your history by itself, one command at a time.
#
# Why write straight into SQLite instead of calling `atuin history start/end`?
# Because that pair of commands always stamps an entry with the *current* time, so
# every seeded command would share the same timestamp. A convincing demo needs a
# history spread over several weeks, which means setting `timestamp` ourselves.
#
# Schema of the `history` table (atuin 18.x):
#   id        text  - primary key, 32 hex chars
#   timestamp int   - NANOSECONDS since the epoch
#   duration  int   - NANOSECONDS
#   exit      int   - exit code of the command
#   command   text
#   cwd       text  - directory the command was run from
#   session   text  - groups commands belonging to the same shell session
#   hostname  text  - "<host>:<user>"
# with a unique(timestamp, cwd, command) constraint.

set -euo pipefail

readonly DB="${HOME}/.local/share/atuin/history.db"

# Let Atuin create the database and run its migrations before we write into it.
atuin search --limit 1 >/dev/null 2>&1 || true

if [[ ! -f "${DB}" ]]; then
    echo "Atuin database not found at ${DB}" >&2
    exit 1
fi

# The container may be restarted; only seed an empty database.
if [[ "$(sqlite3 "${DB}" 'SELECT COUNT(*) FROM history;')" -gt 0 ]]; then
    exit 0
fi

now="$(date +%s)"
me="$(whoami)"

# Two hosts, so the demo can show filtering by machine, and three shell sessions,
# so the "session" filter has something to group.
HOST_LOCAL="$(hostname):${me}"
HOST_REMOTE="srv-prod:${me}"
readonly HOST_LOCAL HOST_REMOTE

new_id() { sqlite3 "${DB}" 'SELECT lower(hex(randomblob(16)));'; }

session_1="$(new_id)"
session_2="$(new_id)"
session_3="$(new_id)"

# Each row: minutes_ago | exit | duration_ms | session | host | cwd | command
#
# "HOME" in the cwd column is replaced by the real $HOME at seeding time, and "L"/"R"
# in the host column select the local or the remote hostname.
#
# Keep minutes_ago strictly increasing-ish and unique enough to satisfy the
# unique(timestamp, cwd, command) constraint; a per-row jitter is added below.
read -r -d '' SEED <<'ROWS' || true
12|0|1840|3|L|HOME/projects/blog|docker compose up -d
15|0|320|3|L|HOME/projects/blog|git status
18|1|90|3|L|HOME/projects/blog|git push origin main
21|0|140|3|L|HOME/projects/blog|git pull --rebase
26|0|12400|3|L|HOME/projects/blog|yarn build
34|0|760|3|L|HOME/projects/blog|yarn lint
41|0|95|3|L|HOME/projects/blog|rg --type md "atuin" .
47|0|210|3|L|HOME/projects/blog|fzf --preview 'bat --color=always {}'
55|127|30|3|L|HOME/projects/blog|yarnn start
58|0|45|3|L|HOME/projects/blog|yarn start
180|0|3200|2|L|HOME/projects/api|docker build -t api:dev .
185|0|880|2|L|HOME/projects/api|docker run --rm -it api:dev bash
190|1|2100|2|L|HOME/projects/api|composer install
196|0|45300|2|L|HOME/projects/api|composer update
205|0|6700|2|L|HOME/projects/api|./vendor/bin/phpunit --testdox
212|1|5400|2|L|HOME/projects/api|./vendor/bin/phpunit --filter UserTest
219|0|130|2|L|HOME/projects/api|php -l src/Controller/UserController.php
228|0|310|2|L|HOME/projects/api|git diff --stat
240|0|88|2|L|HOME/projects/api|git log --oneline -10
255|0|1500|2|L|HOME/projects/api|docker compose logs -f --tail=100 api
1450|0|760|1|L|HOME|ssh srv-prod
1455|0|220|1|R|/var/www/app|tail -f /var/log/nginx/error.log
1462|0|95|1|R|/var/www/app|systemctl status nginx
1470|1|140|1|R|/var/www/app|systemctl restart nginx
1478|0|60|1|R|/var/www/app|sudo systemctl restart nginx
1486|0|310|1|R|/var/www/app|df -h
1494|0|180|1|R|/var/www/app|du -sh /var/log/*
1510|0|2400|1|R|/var/www/app|docker system prune -af
1530|0|120|1|R|/var/www/app|docker ps --format 'table {{.Names}}\t{{.Status}}'
2880|0|430|1|L|HOME/projects/blog|git checkout -b feat/atuin
2890|0|15200|1|L|HOME/projects/blog|npx docusaurus build
2905|0|640|1|L|HOME/projects/blog|git add . && git commit -m "draft: atuin article"
4320|0|980|2|L|HOME/.config|vim ~/.bashrc
4330|0|75|2|L|HOME/.config|source ~/.bashrc
4340|0|1200|2|L|HOME/.config|curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
4355|0|210|2|L|HOME/.config|atuin import auto
5760|0|3400|1|L|HOME/projects/infra|terraform plan
5790|1|8900|1|L|HOME/projects/infra|terraform apply
5820|0|11200|1|L|HOME/projects/infra|terraform apply -auto-approve
7200|0|540|3|L|HOME/projects/blog|wsl --shutdown
7230|0|180|3|L|HOME/projects/blog|ollama run llama3 "summarize this changelog"
7260|0|4100|3|L|HOME/projects/blog|ollama pull mistral
10080|0|2300|2|L|HOME/projects/api|tar -czf backup-$(date +%F).tar.gz ./storage
10110|1|60|2|L|HOME/projects/api|tar -xzf backup.tar.gz -C /tmp/restore
10140|0|85|2|L|HOME/projects/api|mkdir -p /tmp/restore && tar -xzf backup.tar.gz -C /tmp/restore
14400|0|320|1|L|HOME|find . -name "*.log" -mtime +30 -delete
14430|0|1800|1|L|HOME|rsync -avz --progress ./photos/ backup:/mnt/photos/
20160|0|150|3|L|HOME/projects/blog|sed -i 's/foo/bar/g' README.md
20190|0|95|3|L|HOME/projects/blog|awk -F',' '{print $2}' data.csv | sort -u
28800|0|260|2|L|HOME/projects/api|jq '.dependencies | keys' package.json
28830|0|70|2|L|HOME/projects/api|curl -s localhost:8080/health | jq .
ROWS

# Build one big transaction rather than one sqlite3 call per row.
{
    echo "BEGIN;"
    jitter=0
    while IFS='|' read -r mins code dur_ms sess host cwd cmd; do
        [[ -z "${mins}" ]] && continue

        jitter=$((jitter + 7))
        ts_ns=$(( (now - mins * 60 - jitter) * 1000000000 ))
        dur_ns=$(( dur_ms * 1000000 ))

        case "${sess}" in
            1) session="${session_1}" ;;
            2) session="${session_2}" ;;
            *) session="${session_3}" ;;
        esac

        [[ "${host}" == "R" ]] && hostname_value="${HOST_REMOTE}" || hostname_value="${HOST_LOCAL}"

        cwd="${cwd/#HOME/${HOME}}"
        # Escape single quotes for SQL string literals.
        cmd="${cmd//\'/\'\'}"

        printf "INSERT INTO history (id, timestamp, duration, exit, command, cwd, session, hostname) VALUES (lower(hex(randomblob(16))), %s, %s, %s, '%s', '%s', '%s', '%s');\n" \
            "${ts_ns}" "${dur_ns}" "${code}" "${cmd}" "${cwd}" "${session}" "${hostname_value}"
    done <<< "${SEED}"
    echo "COMMIT;"
} | sqlite3 "${DB}"

printf 'Atuin history seeded with %s commands.\n' "$(sqlite3 "${DB}" 'SELECT COUNT(*) FROM history;')"
```

```bash
$ docker build -t atuin-demo .
[+] Building 28.3s (8/8) FINISHED
✔ exporting to image
$ docker run --rm -it atuin-demo
Atuin history seeded with 51 commands.
root@4f2a1b3c9d8e:/#
```

Ne tapez rien — appuyez tout de suite sur `CTRL`+`R` :

```bash
[atuin] > _
──────────────────────────────────────────────────────────────────────────
1  [exit 0]  1s     12m   ~/projects/blog  docker compose up -d
2  [exit 0]  320ms  15m   ~/projects/blog  git status
3  [exit 1]  90ms   18m   ~/projects/blog  git push origin main
4  [exit 0]  140ms  21m   ~/projects/blog  git pull --rebase
5  [exit 0]  12s    26m   ~/projects/blog  yarn build
6  [exit 0]  760ms  34m   ~/projects/blog  yarn lint
7  [exit 0]  95ms   41m   ~/projects/blog  rg --type md "atuin" .
8  [exit 0]  210ms  47m   ~/projects/blog  fzf --preview 'bat --color=always '
9  [exit 127] 30ms  55m   ~/projects/blog  yarnn start
10  [exit 0]  45ms   58m   ~/projects/blog  yarn start
──────────────────────────────────────────────────────────────────────────
↑/↓ navigate  Enter select  Ctrl+D delete  Esc quit
```

Code de sortie, durée, horodatage et répertoire de travail — tout dans une seule vue. L'entrée 9 est typiquement ce que vous ne voyez qu'avec Atuin : une faute de frappe (`yarnn`) morte avec le code 127, juste à côté de la commande corrigée qui a suivi trois minutes plus tard.

Maintenant commencez à taper. Tapez `git` et la liste se réduit aux commandes git ; tapez `docker` et vous atteindrez des commandes lancées dans un *autre* répertoire de projet, et même sur une autre machine — les données de démo couvrent deux noms d'host et trois sessions shell, donc le filtre `CTRL`+`F` a vraiment de quoi travailler.

Cet historique ne sort pas de nulle part : `seed-history.sh` l'écrit directement dans la base SQLite d'Atuin avant le démarrage du shell — son commentaire d'en-tête explique pourquoi, si ça vous intéresse. Passons d'abord à la vraie installation.

## Installer Atuin {#installing-atuin}

Si vous voulez garder Atuin en permanence sur votre machine (et ce sera le cas, après la démo), utilisez votre gestionnaire de packages. Atuin est dans tous les habituels, et c'est de loin la façon la moins excitante de l'obtenir — c'est exactement ce qu'on attend d'une installation.

### Utilisez simplement Homebrew {#just-use-homebrew}

```bash
$ brew install atuin
```

C'est tout. La formule `atuin` de Homebrew suit l'upstream de près — 18.22.0 au moment où j'écris, la même version que la dernière release GitHub — et elle fournit une bottle précompilée pour **Linux comme pour macOS**, donc c'est tout autant la bonne réponse dans WSL.

La formule elle-même est publique et relue via une pull request, le binaire vient d'une bottle construite par la CI de Homebrew, et `brew upgrade atuin` le maintiendra à jour ensuite — vous n'aurez pas besoin de revenir sur cette page pour ça.

**Vous n'avez pas encore Homebrew ?**

Installer Homebrew implique un `curl` redirigé dans `bash` — j'ai fait exactement ça [dans un article précédent](/blog/reduce-image-size), et c'est la commande que brew\.sh publie. Inutile de prétendre le contraire.

Une chose en fait un marché plus honnête que la plupart : le script vit dans le repository public [`Homebrew/install`](https://github.com/Homebrew/install), vous pouvez donc épingler une révision que vous avez réellement lue plutôt que d'exécuter ce qui traîne sur la branch aujourd'hui.

```bash
SHA=8949852f785a3bacaba2a979d0790337950b0a4a
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/${SHA}/install.sh)"
```

Sur Apple Silicon vous pouvez éviter tout ça : Homebrew fournit un [`Homebrew.pkg`](https://github.com/Homebrew/brew/releases/latest) signé.

> **Il n'y a pas de package apt:**
>
> Atuin n'est **pas** dans les repositories Debian ou Ubuntu, donc ne cherchez pas `apt install atuin`. Si vous avez une toolchain Rust, `cargo install atuin` est une autre voie honnête : il construit depuis les sources publiées plutôt que de faire confiance à un binaire précompilé.

### Sous Windows : winget {#on-windows-winget}

Le lecteur habituel de ce blog tourne sous WSL, donc celui-ci mérite un mot à part. Atuin est dans le Windows Package Manager :

```bash
PS> winget install -e --id Atuinsh.Atuin
```

Même forme de garantie qu'avec Homebrew : le manifeste vit dans le repository public `microsoft/winget-pkgs`, relu par pull request, et il épingle le SHA-256 de l'installeur — winget refuse donc tout ce qui ne correspond pas.

> **Windows et WSL, deux historiques distincts:**
>
> `winget` installe `atuin.exe`, le build Windows — il vous donne Atuin dans PowerShell et CMD, **pas** dans votre shell WSL. Si vous vivez dans WSL, l'historique qui vous intéresse vraiment est celui enregistré par le binaire *Linux*, installé dans votre distribution, avec sa propre base sous `~/.local/share/atuin/`. Installez les deux si vous voulez les deux ; ce sont deux installations et deux historiques sans rapport.

### Sans gestionnaire de packages {#without-a-package-manager}

**Télécharger le binaire de la release et le vérifier**

Chaque release fournit un binaire simple. Prenez le build **musl** : il est lié statiquement et tourne partout, alors que le `-gnu` veut une glibc récente et meurt avec `GLIBC_2.39 not found` sur les distributions plus anciennes.

```bash
$ V=18.22.0
$ BASE=https://github.com/atuinsh/atuin/releases/download/v$V
$ curl -fsSLO $BASE/atuin-x86_64-unknown-linux-musl.tar.gz
$ curl -fsSLO $BASE/atuin-x86_64-unknown-linux-musl.tar.gz.sha256
$ sha256sum -c atuin-x86_64-unknown-linux-musl.tar.gz.sha256
atuin-x86_64-unknown-linux-musl.tar.gz: OK
```

Ensuite, mettez-le dans votre `PATH` :

```bash
$ tar -xzf atuin-x86_64-unknown-linux-musl.tar.gz
$ sudo install -m 755 atuin-x86_64-unknown-linux-musl/atuin /usr/local/bin/atuin
$ atuin --version
atuin 18.22.0
```

Les releases d'Atuin embarquent aussi des [attestations de build signées](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) — une preuve cryptographique du workflow qui a construit le binaire, vérifiable avec `gh attestation verify`. Bon à savoir ; pas indispensable pour démarrer.

### En dernier recours : le one-liner officiel {#last-resort-the-official-one-liner}

La documentation d'Atuin met en avant un `curl` redirigé directement dans `sh`. Vous le croiserez partout, donc je ne vais pas prétendre qu'il n'existe pas — mais vous devrez aller le chercher, et lire ceci d'abord.

> **Ceci confie votre machine à qui contrôle ce domaine:**
>
> `curl … | sh` télécharge un script et l'exécute **immédiatement**, avec vos propres droits, sans que vous en voyiez une seule ligne. Si `setup.atuin.sh` est compromis un jour — domaine détourné, identifiant fuité, entrée CDN empoisonnée — alors ce que l'attaquant y a laissé s'exécute sur votre machine dès que vous appuyez sur Entrée. Aucune signature à vérifier, aucune révision à épingler, aucun diff à lire, et aucune trace ensuite.
>
> Les flags `--proto '=https' --tlsv1.2` ne sont pas la garantie qu'ils semblent être : ils sécurisent le *transport*, et ne disent absolument rien du contenu qui arrive.
>
> Utilisez `brew install atuin` plus haut, ou l'installation du binaire vérifié juste au-dessus. Ne recourez à celle-ci que sur une machine qui n'a ni l'un ni l'autre.
>
> **Je comprends le risque — montrez-moi la commande quand même**
>
> ```bash
> $ curl --proto '=https' --tlsv1.2 -LsSf https://setup.atuin.sh | sh
> ```

## Brancher Atuin dans votre shell {#wiring-atuin-into-your-shell}

Quelle que soit la route choisie, le binaire est sur votre machine mais votre shell ignore encore son existence — `CTRL`+`R` est inchangé pour l'instant. Le brancher tient en deux lignes, et ce sont justement les deux lignes qui valent la peine d'être comprises.

### Bash {#bash}

Ajoutez ces deux lignes à la **fin** de votre `~/.bashrc` :

```bash title="~/.bashrc"
source /path/to/bash-preexec.sh   # skip if you're on Bash 4.4+
eval "$(atuin init bash)"
```

> **bash-preexec sur Bash moderne:**
>
> `bash-preexec` est une petite bibliothèque de hooks qui donne à Bash le mécanisme `precmd` / `preexec` que ZSH possède nativement ; Atuin l'utilise pour intercepter une commande avant et après son exécution, ce qui lui permet d'enregistrer le code de sortie et la durée. Sur Bash 4.4+ (la plupart des distributions Linux récentes), c'est optionnel. Atuin retombe sur un hook plus simple. Si vous voulez le suivi complet du code de sortie et de la durée, gardez `bash-preexec`. Sur Ubuntu 24.04 (Bash 5.2), ça marche très bien sans — mais la démo Docker l'inclut pour une compatibilité maximale.

Puis rechargez votre shell :

```bash
$ source ~/.bashrc
```

### ZSH {#zsh}

Si vous utilisez déjà ZSH (et vous devriez — [voici comment le mettre en place](/blog/zsh-install)), Atuin s'intègre encore plus proprement car ZSH a des hooks `preexec`/`precmd` natifs. Aucune dépendance supplémentaire.

Ajoutez à `~/.zshrc` :

```zsh title="~/.zshrc"
eval "$(atuin init zsh)"
```

Puis rechargez :

```bash
$ source ~/.zshrc
```

Si vous suivez [un workflow ZSH modulaire](/blog/modular-zsh-workflow), placez la ligne `eval` dans son propre fichier — par ex. `~/.zsh/plugins/atuin.zsh` — et sourcez-le depuis votre `~/.zshrc` principal. Ça garde votre config propre et facile à activer/désactiver.

## Importer votre historique existant {#import-your-existing-history}

Atuin importe votre `~/.bash_history` ou `~/.zsh_history` actuel au premier lancement. Vous pouvez aussi le déclencher manuellement :

```bash
$ atuin import auto
✓  Importing history from /home/christophe/.bash_history
Imported 4 823 commands
```

Vos anciennes commandes sont maintenant dans la base avec leurs horodatages d'origine (s'il y en avait). Vous ne perdez rien.

## Configurer Atuin {#configuring-atuin}

La configuration d'Atuin vit dans `~/.config/atuin/config.toml`. Les valeurs par défaut sont raisonnables, mais quelques options valent le détour :

```toml title="~/.config/atuin/config.toml"
# How many results to show in the TUI
search_mode = "fuzzy"      # or "prefix", "fulltext"

# Filter by current directory by default (toggle with CTRL+F in the TUI)
filter_mode = "global"     # or "host", "session", "directory"

# Show the full command, not a truncated one
show_preview = true

# Inline TUI instead of full-screen overlay
style = "compact"          # or "full" (default), "auto"
```

Redémarrez votre shell après édition pour appliquer les changements.

## Atuin vs. l'historique FZF {#atuin-vs-fzf-history}

[FZF](/blog/linux-fzf-introduction) est la référence absolue de la recherche floue dans le terminal — y compris pour l'historique shell via `CTRL`+`R` quand il est branché avec le `fzf-history-widget`. Alors, comment Atuin se compare-t-il ?

| Fonctionnalité                      | Atuin                           | FZF + history                            |
| ----------------------------------- | ------------------------------- | ---------------------------------------- |
| **Backend**                         | Base SQLite                     | Fichier texte plat                       |
| **Horodatage**                      | Toujours enregistré             | Seulement si `HISTTIMEFORMAT` est défini |
| **Code de sortie**                  | Oui                             | Non                                      |
| **Durée**                           | Oui                             | Non                                      |
| **Répertoire de travail**           | Oui                             | Non                                      |
| **Synchro multi-machines**          | Oui (optionnelle, chiffrée E2E) | Non                                      |
| **Recherche floue**                 | Oui (intégrée)                  | Oui (via FZF)                            |
| **Filtrer par répertoire**          | Oui (`CTRL+F` dans la TUI)      | Non                                      |
| **Filtrer par host**                | Oui                             | Non                                      |
| **Shells supportés**                | Bash, ZSH, Fish, Nu             | Bash, ZSH, Fish                          |
| **Dépendances**                     | Un binaire                      | Binaire FZF + plugin shell               |
| **Import de l'historique existant** | Oui                             | N/A (lit déjà le même fichier)           |
| **Configuration**                   | Fichier TOML                    | Flags en variables de shell              |
| **TUI**                             | Panneau plein écran             | En ligne (ou plein avec `--height=100%`) |

Aucun des deux n'est strictement meilleur — ça dépend de vos besoins :

* **Utilisez FZF** si vous l'avez déjà branché dans votre workflow pour autre chose (recherche de fichiers, branches git, contextes kubectl…) et que vous n'avez besoin que d'une recherche inversée basique. L'intégration FZF de `CTRL`+`R` est légère et ne demande ni daemon ni base de données.
* **Utilisez Atuin** si vous vous souciez du **pourquoi** une commande a tourné (code de sortie, durée, répertoire) et que vous voulez un historique qui survit aux migrations de machine et se corrèle entre hosts. Le modèle base de données rend la recherche d'Atuin structurellement plus riche.

Ils ne sont pas mutuellement exclusifs. Certains font tourner les deux : Atuin pour `CTRL`+`R` (recherche structurée et horodatée) et FZF pour tout le reste (navigation de fichiers, complétions floues). [Combiner FZF avec ripgrep](/blog/fzf-ripgrep) pour la recherche dans le code reste un cas d'usage différent auquel Atuin ne touche jamais.

> **Désactiver le CTRL+R d'Atuin pour garder celui de FZF:**
>
> Si vous voulez qu'Atuin enregistre l'historique en silence tout en gardant le binding `CTRL`+`R` de FZF, ajoutez ceci à votre config :
>
> ```toml title="~/.config/atuin/config.toml"
> [keys]
> scroll_exits = false
> ```
>
> Et dans votre shell, bindez manuellement `CTRL`+`R` sur `fzf-history-widget` après avoir sourcé Atuin. Atuin continuera de capturer et stocker les commandes ; il n'interceptera juste plus la touche.

## Conclusion {#conclusion}

La recherche inversée `CTRL`+`R` par défaut a été conçue à une époque où 500 commandes paraissaient largement suffisantes. Ce n'est plus le cas — pas quand vous jonglez entre builds Docker, workflows git, sessions SSH sur une demi-douzaine d'hosts et fonctions shell qui ont pris une heure à mettre au point. Atuin donne à cet historique la structure qu'il mérite : une vraie base de données, de vrais horodatages, un vrai contexte.

La démo Docker est la meilleure façon de sentir la différence sans engagement. Lancez-la, appuyez sur `CTRL`+`R`, et trois semaines d'historique sont déjà là à vous attendre — vous verrez immédiatement pourquoi un fichier plat ne suffit pas. Si vous êtes déjà [FZF user](/blog/linux-fzf-introduction), ne voyez pas Atuin comme un remplaçant — voyez-le comme ce qui arrive quand on applique le principe « les données structurées battent le texte brut » à l'outil que vous utilisez plus que tous les autres.

Maintenant, chaque fois que je me trompe sur cette incantation `tar` parfaite ou que j'oublie dans quel répertoire j'étais quand ce script a enfin marché, Atuin s'en souviendra pour moi.
