La commande `history` sous Linux : Guide complet de l’historique Bash
La commande `history` sous Linux est un utilitaire intégré du shell Bash qui enregistre, affiche et gère chaque commande exécutée dans une session de terminal. Elle lit et écrit dans `~/.bash_history`, un fichier texte brut dans le répertoire personnel de chaque utilisateur, vous permettant de rappeler, rechercher, réexécuter et auditer des commandes entre les sessions sans les retaper.
Pour les administrateurs système et les utilisateurs avancés, l’historique Bash n’est pas simplement une fonctionnalité pratique — c’est une piste d’audit opérationnelle, un outil de débogage et un multiplicateur de productivité. Comprendre son fonctionnement interne, ses variables de configuration et ses implications en matière de sécurité distingue les utilisateurs occasionnels des ingénieurs qui tirent le maximum de valeur de la ligne de commande.
Fonctionnement interne de l’historique Bash
Lorsque vous ouvrez une session de terminal, Bash charge le contenu de `~/.bash_history` dans une liste en mémoire. Au fur et à mesure que vous exécutez des commandes, elles sont ajoutées à ce tampon en mémoire. Lorsque la session se ferme normalement (via `exit` ou `logout`), le tampon est réécrit dans `~/.bash_history` selon les règles définies par vos variables d’environnement.
Cette architecture a une implication critique : si votre session se termine anormalement (coupure de courant, déconnexion SSH, `kill -9`), les commandes de cette session peuvent ne jamais être écrites sur le disque. C’est une source fréquente de confusion lorsque les administrateurs perdent la trace des commandes exécutées lors d’une session interrompue.
Deux options du shell modifient ce comportement d’écriture par défaut à la fermeture :
- `shopt -s histappend` — ajoute le nouvel historique à `~/.bash_history` au lieu de l’écraser. Ceci est essentiel dans les environnements multi-sessions.
- `PROMPT_COMMAND='history -a'` — force Bash à ajouter la dernière commande au fichier d’historique après chaque invite, permettant une persistance en temps réel et une visibilité entre les terminaux.
Sans `histappend`, le dernier shell à se fermer l’emporte — il écrase le fichier d’historique, supprimant silencieusement les entrées de toutes les autres sessions simultanées.
Utilisation de base de la commande `history`
Afficher l’historique complet des commandes
“`bash
history
“`
Affiche une liste numérotée des commandes enregistrées. Le numéro à gauche est l’index d’historique, utilisé pour les désignateurs d’événements.
Afficher un nombre spécifique de commandes récentes
“`bash
history 20
“`
Affiche les 20 dernières commandes. Utile lorsque vous avez besoin d’un aperçu rapide de l’activité récente sans faire défiler des centaines d’entrées.
Écrire immédiatement l’historique de la session courante dans le fichier
“`bash
history -w
“`
Force une écriture immédiate du tampon d’historique en mémoire vers `~/.bash_history`. Utilisez ceci avant de fermer une session critique pour vous assurer que rien n’est perdu.
Lire l’historique depuis le fichier dans la session courante
“`bash
history -r
“`
Recharge `~/.bash_history` dans la mémoire de la session courante. Utile lorsque vous souhaitez accéder aux commandes saisies dans une autre fenêtre de terminal pendant la même connexion.
Rappel et réexécution des commandes
Désignateurs d’événements avec `!`
La syntaxe des désignateurs d’événements de Bash permet la réexécution directe de commandes historiques par référence :
| Désignateur | Comportement |
|---|
| — | — |
|---|
| `!!` | Réexécute la commande précédente immédiate |
|---|
| `!n` | Exécute la commande à l’index d’historique `n` |
|---|
| `!-n` | Exécute la commande `n` positions en arrière depuis la position actuelle |
|---|
| `!string` | Exécute la commande la plus récente commençant par `string` |
|---|
| `!?string?` | Exécute la commande la plus récente contenant `string` n’importe où |
|---|
| `!$` | Substitue le dernier argument de la commande précédente |
|---|
| `!*` | Substitue tous les arguments de la commande précédente |
|---|
Exemple pratique — réutilisation du dernier argument :
“`bash
mkdir /var/www/myproject
cd !$
“`
`!$` se développe en `/var/www/myproject`, vous évitant de retaper le chemin. C’est l’une des fonctionnalités les plus sous-utilisées mais les plus utiles de l’historique Bash.
Prévisualisation avant exécution :
Ajoutez `:p` à n’importe quel désignateur d’événement pour afficher la commande sans l’exécuter :
“`bash
!42:p
“`
C’est une habitude de sécurité critique lorsque vous travaillez sur des serveurs de production. Prévisualisez toujours les commandes destructives avant leur exécution.
Désignateurs de mots pour l’extraction d’arguments
Au-delà de la réexécution de commandes entières, Bash vous permet d’extraire des arguments spécifiques des entrées d’historique :
“`bash
!!:2 # Second word (argument) of the last command
!!:1-3 # Words 1 through 3 of the last command
!ssh:$ # Last argument of the most recent ssh command
“`
Ce niveau de granularité est inestimable lors de la construction de pipelines complexes ou de la répétition d’opérations sur les mêmes chemins de fichiers.
Raccourcis clavier pour la navigation dans l’historique
| Raccourci | Action |
|---|
| — | — |
|---|
| `Up Arrow` / `Ctrl+P` | Aller à la commande précédente |
|---|
| `Down Arrow` / `Ctrl+N` | Aller à la commande suivante |
|---|
| `Ctrl+R` | Recherche incrémentale inversée dans l’historique |
|---|
| `Ctrl+S` | Recherche incrémentale vers l’avant (nécessite `stty -ixon`) |
|---|
| `Alt+.` | Insérer le dernier argument de la commande précédente |
|---|
| `Ctrl+G` | Annuler la recherche dans l’historique en cours |
|---|
Remarque sur `Ctrl+S` : Par défaut, `Ctrl+S` déclenche le contrôle de flux XON/XOFF et gèle le terminal. Pour activer la recherche vers l’avant dans l’historique, ajoutez `stty -ixon` à votre `~/.bashrc`.
Recherche inversée avec `Ctrl+R`
“`
(reverse-i-search)`git': git commit -am "fix: resolve race condition"
“`
Saisissez une sous-chaîne et Bash fait correspondre de manière incrémentale la commande la plus récente la contenant. Appuyez à nouveau sur `Ctrl+R` pour passer aux correspondances plus anciennes. Appuyez sur `Enter` pour exécuter, ou sur `Ctrl+G` pour annuler sans rien exécuter.
Pour les recherches dans l’historique à volume élevé, redirigez vers `grep` :
“`bash
history | grep "docker run"
history | grep -E "^[[:space:]]+[0-9]+[[:space:]]+ssh"
“`
Modification et gestion des entrées d’historique
Supprimer une entrée spécifique
“`bash
history -d 87
“`
Supprime la commande à l’index 87 de la liste en mémoire. Pour rendre cela permanent, suivez avec `history -w` pour réécrire la liste modifiée sur le disque.
Supprimer une plage d’entrées
“`bash
for i in $(seq 85 90); do history -d 85; done
“`
Comme la suppression décale les indices, supprimez toujours le même numéro d’index dans une boucle plutôt que de l’incrémenter.
Effacer tout l’historique en mémoire
“`bash
history -c
“`
Efface le tampon d’historique de la session courante. Cela ne touche pas `~/.bash_history` sur le disque.
Purger complètement tout l’historique
“`bash
history -c && history -w
“`
Efface le tampon en mémoire puis écrit le tampon vide dans `~/.bash_history`, tronquant effectivement le fichier. C’est la séquence correcte en deux étapes — utiliser `> ~/.bash_history` seul ne vide pas le tampon en mémoire, donc le fichier peut être repeuplé à la fermeture de la session.
Configuration de l’historique Bash : variables d’environnement
Tout le comportement de l’historique est régi par des variables d’environnement, généralement définies dans `~/.bashrc` (shells interactifs non-login) ou `~/.bash_profile` / `~/.profile` (shells login). Les modifications prennent effet après avoir sourcé le fichier :
“`bash
source ~/.bashrc
“`
`HISTSIZE`
Contrôle le nombre de commandes conservées en mémoire pendant une session active.
“`bash
export HISTSIZE=10000
“`
Définir cette valeur à `0` désactive entièrement l’historique en mémoire. La définir à `-1` (dans Bash 4.3+) la rend illimitée.
`HISTFILESIZE`
Contrôle le nombre maximum de lignes stockées dans `~/.bash_history` sur le disque.
“`bash
export HISTFILESIZE=20000
“`
Lorsque le fichier dépasse cette limite, Bash supprime les entrées les plus anciennes. Pour les environnements sensibles à la conformité, définissez cette valeur à un grand nombre et associez-la à la rotation des journaux.
`HISTCONTROL`
Détermine les règles de filtrage pour les commandes qui sont enregistrées.
| Valeur | Comportement |
|---|
| — | — |
|---|
| `ignoredups` | Ignore les commandes dupliquées consécutives |
|---|
| `ignorespace` | Ignore les commandes préfixées par un espace |
|---|
| `ignoreboth` | Combine les deux options ci-dessus |
|---|
| `erasedups` | Supprime toutes les occurrences précédentes d’une commande avant d’ajouter la nouvelle |
|---|
“`bash
export HISTCONTROL=ignoreboth
“`
Cas d’utilisation sécuritaire pour `ignorespace` : Préfixez toute commande contenant un mot de passe ou un secret avec un espace pour éviter qu’elle soit enregistrée :
“`bash
mysql -u root -pSuperSecretPassword
“`
C’est une pratique de sécurité opérationnelle largement utilisée sur les systèmes partagés ou multi-utilisateurs.
`HISTTIMEFORMAT`
Ajoute un horodatage à chaque entrée d’historique, stocké sous forme de ligne de commentaire dans `~/.bash_history`.
“`bash
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
“`
Exemple de sortie :
“`
487 2024-11-14 09:32:17 systemctl restart nginx
488 2024-11-14 09:32:45 tail -f /var/log/nginx/error.log
“`
Les horodatages sont essentiels pour la forensique post-incident sur les environnements d’hébergement VPS et les infrastructures dédiées. Sans eux, vous savez *ce qui* a été exécuté mais pas *quand*.
`HISTIGNORE`
Une liste de motifs glob séparés par des deux-points. Les commandes correspondant à n’importe quel motif ne sont pas sauvegardées dans l’historique.
“`bash
export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:history"
“`
Cela empêche les commandes triviales de polluer votre historique et de diluer les résultats de recherche. Vous pouvez également utiliser des caractères génériques :
“`bash
export HISTIGNORE="*password*:*secret*:*token*"
“`
C’est une mesure de défense en profondeur — combinez-la avec `ignorespace` pour une hygiène maximale des identifiants.
Tableau de référence complet des variables de configuration de l’historique Bash
| Variable | Valeur par défaut | Objectif |
|---|
| — | — | — |
|---|
| `HISTSIZE` | 500–1000 | Commandes conservées en mémoire par session |
|---|
| `HISTFILESIZE` | 500–2000 | Lignes stockées dans `~/.bash_history` |
|---|
| `HISTCONTROL` | (non défini) | Règles de filtrage pour les commandes enregistrées |
|---|
| `HISTTIMEFORMAT` | (non défini) | Format d’horodatage ajouté en préfixe aux entrées |
|---|
| `HISTIGNORE` | (non défini) | Motifs glob pour les commandes à exclure |
|---|
| `HISTFILE` | `~/.bash_history` | Chemin vers le fichier d’historique |
|---|
| `histappend` (shopt) | off | Ajout vs. écrasement à la fermeture de session |
|---|
Partage de l’historique entre plusieurs sessions de terminal
Par défaut, chaque session Bash maintient son propre tampon d’historique isolé. Les commandes saisies dans le Terminal A sont invisibles pour le Terminal B jusqu’à ce que les deux sessions se ferment et que le fichier soit écrit. Pour les administrateurs gérant plusieurs sessions SSH simultanément sur des serveurs dédiés, cela crée des lacunes dans l’enregistrement opérationnel.
La configuration recommandée pour le partage d’historique en temps réel entre sessions :
“`bash
~/.bashrc
export HISTSIZE=100000
export HISTFILESIZE=100000
export HISTCONTROL=ignoreboth
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
shopt -s histappend
PROMPT_COMMAND='history -a; history -c; history -r'
“`
Ce que cela fait :
- `history -a` — ajoute la dernière commande au fichier
- `history -c` — efface le tampon en mémoire
- `history -r` — recharge le fichier en mémoire
Après chaque commande, chaque session de terminal voit l’historique complet et unifié de toutes les sessions actives. La contrepartie est une légère surcharge sur l’exécution de `PROMPT_COMMAND`, ce qui est négligeable en pratique.
Recherche efficace dans l’historique : techniques avancées
`fzf` — Recherche floue dans l’historique
L’outil `fzf` transforme la recherche dans l’historique d’un balayage linéaire en une interface de correspondance floue interactive :
“`bash
Install fzf (Debian/Ubuntu)
sudo apt install fzf
Bind Ctrl+R to fzf-powered history search
Add to ~/.bashrc:
[ -f ~/.fzf.bash ] && source ~/.fzf.bash
“`
Une fois configuré, `Ctrl+R` ouvre une recherche floue en plein écran sur tout votre historique. C’est particulièrement puissant avec de grands fichiers d’historique (plus de 10 000 entrées) où `grep` devient fastidieux.
Extraction de l’historique pour les scripts
“`bash
Export all unique commands containing "iptables" to a script
history | grep iptables | awk '{$1=""; print $0}' | sort -u > iptables_audit.sh
“`
Ce modèle est utile pour reconstruire des runbooks à partir de commandes ad-hoc exécutées lors d’une réponse à un incident.
Considérations de sécurité pour l’historique Bash
L’historique Bash est un outil à double tranchant. Il accélère les flux de travail légitimes mais représente également une surface d’attaque significative.
Principaux risques et mesures d’atténuation :
- Exposition des identifiants : Les mots de passe passés comme arguments de ligne de commande (par exemple, `curl -u admin:password`) sont stockés en texte brut dans `~/.bash_history`. Utilisez plutôt `ignorespace`, `HISTIGNORE`, ou des variables d’environnement.
- Forensique d’escalade de privilèges : Les attaquants qui obtiennent un accès shell lisent systématiquement `~/.bash_history` pour comprendre l’environnement, découvrir des identifiants et identifier des cibles de valeur. Définissez des permissions restrictives : `chmod 600 ~/.bash_history`.
- Falsification de l’historique : Un utilisateur compromis peut exécuter `history -c && history -w` pour effacer toutes les preuves. À des fins d’audit sur les systèmes de production, envisagez une journalisation des commandes basée sur `auditd` ou `syslog`, qui ne peut pas être manipulée par l’utilisateur.
- Isolation de l’historique root : L’historique de l’utilisateur root est stocké dans `/root/.bash_history`. Assurez-vous que ce fichier n’est pas lisible par tous et qu’il est inclus dans votre périmètre de sauvegarde et d’audit.
Pour les environnements nécessitant un audit strict des commandes — tels que les infrastructures conformes PCI-DSS ou SOC 2 — l’historique Bash seul est insuffisant. Associez-le à un audit au niveau du noyau via `auditd` et à l’expédition centralisée des journaux.
Historique Bash vs. autres systèmes d’historique de shell
| Fonctionnalité | Historique Bash | Historique Zsh | Historique Fish |
|---|
| — | — | — | — |
|---|
| Fichier d’historique par défaut | `~/.bash_history` | `~/.zsh_history` | `~/.local/share/fish/fish_history` |
|---|
| Support des horodatages | Via `HISTTIMEFORMAT` | Intégré | Intégré (format YAML) |
|---|
| Gestion des doublons | `HISTCONTROL` | Option `HIST_IGNORE_DUPS` | Déduplication automatique |
|---|
| Partage entre sessions | Manuel (`PROMPT_COMMAND`) | Option `INC_APPEND_HISTORY` | Automatique (partagé par défaut) |
|---|
| Interface de recherche | `Ctrl+R` (linéaire) | `Ctrl+R` (linéaire) | Mise en évidence syntaxique, contextuelle |
|---|
| Taille maximale de l’historique | Variable `HISTFILESIZE` | Variable `SAVEHIST` | Pas de limite stricte |
|---|
| Mécanisme de verrouillage | Aucun (conditions de concurrence possibles) | Verrouillage de fichier supporté | Basé sur SQLite (écritures atomiques) |
|---|
La principale limitation de l’historique Bash est l’absence de verrouillage intégré, ce qui peut provoquer des conditions de concurrence lorsque plusieurs sessions écrivent simultanément. Zsh et Fish gèrent cela plus élégamment au niveau du shell.
Configuration pratique pour les environnements de production
Voici une configuration d’historique `~/.bashrc` éprouvée, adaptée aux serveurs Linux de production, y compris ceux exécutant un VPS avec cPanel ou des panneaux de contrôle personnalisés :
“`bash
— Bash History Configuration —
export HISTSIZE=50000
export HISTFILESIZE=50000
export HISTCONTROL=ignoreboth:erasedups
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
export HISTIGNORE="ls:ll:la:cd:pwd:exit:clear:bg:fg:jobs"
export HISTFILE=~/.bash_history
Append to history file; don't overwrite
shopt -s histappend
Save and reload history after each command
PROMPT_COMMAND='history -a; history -c; history -r'
Enable multi-line command history as single entry
shopt -s cmdhist
Store multi-line commands with embedded newlines
shopt -s lithist
“`
`cmdhist` et `lithist` méritent une mention spéciale. Sans `cmdhist`, une commande multi-lignes (comme une boucle `for` saisie de manière interactive) est stockée sous forme de lignes séparées, rendant impossible sa réexécution propre. Avec `cmdhist` activé et `lithist` défini, toute la construction est stockée comme une seule entrée d’historique avec des sauts de ligne littéraux, préservant sa structure.
Automatisation des flux de travail basés sur l’historique
Générer un rapport de fréquence des commandes
“`bash
history | awk '{print $2}' | sort | uniq -c | sort -rn | head -20
“`
Cela révèle vos 20 commandes les plus utilisées — utile pour identifier les candidats aux alias ou aux fonctions shell.
Auditer l’utilisation de `sudo`
“`bash
history | grep sudo | awk '{$1=""; print $0}'
“`
Sur les environnements de panneaux de contrôle VPS partagés, cela fournit un audit rapide des opérations privilégiées effectuées pendant une session.
Reconstruire une chronologie de session
“`bash
HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S " history | grep "2024-11-14"
“`
Filtre toutes les commandes exécutées à une date spécifique — inestimable lors des revues post-incident.
Points techniques clés et liste de contrôle
Avant de déployer une configuration d’historique Bash dans n’importe quel environnement, validez les points suivants :
- `shopt -s histappend` est défini — empêche la perte d’historique due à des sessions concurrentes qui s’écrasent mutuellement
- `HISTSIZE` et `HISTFILESIZE` sont tous deux configurés — définir seulement l’un laisse l’autre à sa valeur par défaut, provoquant une troncature inattendue
- `HISTTIMEFORMAT` est activé — sans horodatages, l’historique n’a aucune valeur forensique
- `HISTCONTROL=ignoreboth` est défini au minimum — réduit le bruit et empêche l’enregistrement des commandes adjacentes aux identifiants
- `HISTIGNORE` exclut les commandes triviales — maintient un bon rapport signal/bruit dans l’historique
- `~/.bash_history` a les permissions `chmod 600` — empêche les autres utilisateurs de lire votre historique de commandes
- `cmdhist` est activé — garantit que les commandes multi-lignes sont stockées comme des unités cohérentes
- `PROMPT_COMMAND` synchronise l’historique en temps réel — requis pour les environnements multi-sessions
- `auditd` est déployé en parallèle — pour les systèmes de production où une journalisation inviolable est requise
- Les identifiants ne sont jamais passés comme arguments CLI — utilisez des variables d’environnement, `.netrc`, ou des gestionnaires de secrets à la place
Questions fréquemment posées
Pourquoi mon historique Bash disparaît-il après la fermeture d’une session SSH ?
Cela se produit généralement parce que `shopt -s histappend` n’est pas défini. Sans cela, chaque session écrase `~/.bash_history` à la fermeture. Si la session se termine anormalement (coupure réseau, `kill -9`), l’écriture ne se produit jamais du tout. Définissez `histappend` et `PROMPT_COMMAND='history -a'` pour persister les commandes en temps réel.
Comment empêcher l’enregistrement des mots de passe dans l’historique Bash ?
Utilisez deux techniques complémentaires : préfixez la commande avec un espace (nécessite `HISTCONTROL=ignorespace` ou `ignoreboth`), et ajoutez les modèles de commandes sensibles à `HISTIGNORE`. Pour une hygiène à long terme, ne passez jamais de secrets comme arguments CLI — utilisez des variables d’environnement ou des outils dédiés à la gestion des secrets.
Quelle est la différence entre `HISTSIZE` et `HISTFILESIZE` ?
`HISTSIZE` contrôle le nombre de commandes que Bash conserve en mémoire pendant une session active. `HISTFILESIZE` contrôle le nombre de lignes conservées dans `~/.bash_history` sur le disque. Les deux doivent être définis explicitement — un grand `HISTSIZE` avec un petit `HISTFILESIZE` signifie que votre historique en session est riche, mais la majeure partie est supprimée à la fermeture de la session.
Les entrées d’historique supprimées peuvent-elles être récupérées ?
Une fois `history -c && history -w` exécuté, le tampon en mémoire est effacé et le fichier est tronqué — la récupération standard n’est pas possible. Cependant, si votre système utilise des instantanés de système de fichiers ou des solutions de sauvegarde, la version précédente de `~/.bash_history` peut être récupérable depuis un instantané. C’est une raison supplémentaire d’implémenter `auditd` pour une journalisation inviolable sur les infrastructures critiques.
Comment partager l’historique Bash entre plusieurs sessions de terminal simultanées ?
Ajoutez ce qui suit à `~/.bashrc` : `shopt -s histappend` et `PROMPT_COMMAND='history -a; history -c; history -r'`. Cela force chaque session à ajouter sa dernière commande au fichier partagé et à recharger le fichier complet après chaque invite, donnant à tous les terminaux actifs une vue unifiée et en temps réel de l’historique des commandes.
