
Fish (Friendly Interactive Shell) est un shell interactif confortable dès l'installation, sans configuration : autosuggestions tirées de l'historique, coloration syntaxique en direct et complétion intelligente sont actives par défaut. Là où Bash et Zsh demandent des heures de réglages pour atteindre ce confort, Fish le fournit d'emblée, au prix d'une syntaxe volontairement non POSIX. Cette page montre comment l'installer, le configurer via config.fish, écrire des fonctions persistantes et éviter le piège du PATH qui duplique silencieusement vos chemins. Les commandes sont validées sur Fish 4.0.2, la version livrée par Debian 13.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Installer Fish sur les principales distributions et l'essayer sans changer de shell par défaut
- Configurer
config.fishet ajouter un chemin auPATHsans le corrompre - Écrire des fonctions persistantes, les déboguer et les supprimer proprement
- Utiliser les vrais raccourcis clavier de Fish, vérifiés avec la commande
bind - Savoir quand ne pas utiliser Fish : les scripts d'administration restent en Bash
Installer Fish
Section intitulée « Installer Fish »Fish est packagé dans les dépôts officiels de toutes les distributions courantes. Aucun dépôt tiers, aucun script d'installation distant : le gestionnaire de paquets de votre distribution suffit, ce qui vous garantit des mises à jour de sécurité suivies par la distribution.
sudo apt updatesudo apt install fishsudo dnf install fishsudo pacman -S fishbrew install fishSi le gestionnaire de paquets apt ne vous est pas familier, le guide apt détaille son fonctionnement. Sous Windows, Fish s'installe dans WSL 2 avec la commande Debian/Ubuntu ci-dessus. Sous macOS, l'installation passe par Homebrew.
Vérification : la commande suivante doit afficher la version installée.
fish --versionfish, version 4.0.2Essayer Fish avant d'en faire votre shell par défaut
Section intitulée « Essayer Fish avant d'en faire votre shell par défaut »Changer de shell par défaut avant d'avoir testé est un risque inutile : si votre config.fish contient une erreur, vous vous retrouvez avec un shell de connexion cassé. La bonne méthode consiste à lancer Fish comme une commande ordinaire, à l'utiliser quelques jours, et à ne basculer qu'ensuite. Vous quittez Fish avec exit et retrouvez votre shell précédent.
fishUne fois convaincu, déclarez Fish comme shell de connexion. La commande chsh refuse tout interpréteur absent du fichier /etc/shells (la liste blanche des shells de connexion autorisés), d'où la vérification préalable.
-
Vérifiez que Fish est déclaré comme shell de connexion valide :
Fenêtre de terminal grep fish /etc/shellsSi la commande ne renvoie rien, ajoutez le chemin de l'exécutable :
Fenêtre de terminal command -v fish | sudo tee -a /etc/shells -
Changez de shell pour votre compte utilisateur. La forme
$(...)est utilisée ici parce qu'elle fonctionne aussi bien depuis Bash que depuis Fish, alors que la forme(...)propre à Fish provoquerait une erreur de syntaxe si vous êtes encore dans Bash :Fenêtre de terminal chsh -s $(command -v fish) -
Vérifiez la prise en compte en relisant la base des comptes, puis reconnectez-vous :
Fenêtre de terminal getent passwd $USERLa ligne doit se terminer par
/usr/bin/fish.
Configurer Fish avec config.fish
Section intitulée « Configurer Fish avec config.fish »Toute la configuration de Fish vit dans ~/.config/fish/. Le fichier ~/.config/fish/config.fish est lu à chaque démarrage d'un shell Fish : c'est là que vous placez vos réglages d'environnement. Le sous-répertoire ~/.config/fish/functions/ contient vos fonctions, chargées automatiquement et à la demande (Fish les lit quand vous appelez la fonction, pas au démarrage).
Pour l'apparence, Fish fournit fish_config, qui ouvre une interface web locale de personnalisation du thème d'invite.
fish_config
Sur un serveur en SSH, aucun navigateur n'est disponible : la même commande fonctionne alors en ligne de commande, ce qui est souvent plus rapide. Vous listez les invites disponibles, puis vous en choisissez une et vous l'enregistrez.
fish_config prompt listacidhubarrowastronautdefaultdiscoinformativefish_config prompt choose informativefish_config prompt saveVérification : ouvrez un nouveau terminal, l'invite doit avoir changé. Le choix est écrit dans ~/.config/fish/functions/fish_prompt.fish.
Ajouter un chemin au PATH sans le dupliquer
Section intitulée « Ajouter un chemin au PATH sans le dupliquer »C'est l'erreur la plus fréquente quand on arrive de Bash, et elle mérite qu'on s'y arrête. En Bash, on écrit export PATH=$PATH:/nouveau/chemin. Transposée telle quelle en Fish, cette ligne ne fait pas ce que vous croyez.
En Fish, une variable est une liste, jamais une chaîne. Coller une chaîne à côté d'une liste ne concatène pas : cela produit un produit cartésien, c'est-à-dire que le suffixe est collé à chaque élément de la liste.
set liste a b cecho $liste:/suffixea:/suffixe b:/suffixe c:/suffixeAppliqué au PATH, l'effet est sournois. Comme PATH est une variable de chemin que Fish redécoupe sur les deux-points, vos commandes continuent de fonctionner, ce qui vous laisse croire que tout va bien. En réalité, vous ajoutez une copie du nouveau chemin par entrée existante, et le PATH double de taille à chaque rechargement de config.fish.
set -gx PATH /usr/bin /binset -gx PATH $PATH:/opt/bin # à ne pas reproduirecount $PATH4Rejouez cette même ligne deux fois de plus, comme le ferait un source ~/.config/fish/config.fish, et le compteur passe à 8 puis 16 entrées. Le PATH enfle jusqu'à ralentir la résolution de chaque commande.
La bonne réponse est fish_add_path, la commande prévue pour cela. Elle est idempotente (l'appeler dix fois n'ajoute qu'une entrée), elle persiste toute seule via la variable universelle fish_user_paths, et elle place le chemin en tête du PATH.
fish_add_path /opt/outils/binVérification : contains renvoie le code de retour 0 quand l'élément est bien présent dans la liste.
contains /opt/outils/bin $PATH; echo $status0Parce que fish_add_path écrit dans une variable universelle, vous n'avez rien à ajouter dans config.fish : le chemin est déjà persistant pour toutes vos sessions. Pour retirer un chemin, agissez sur cette même variable fish_user_paths.
set -U fish_user_paths (string match -v /opt/outils/bin $fish_user_paths)Si vous tenez à passer par config.fish, la syntaxe correcte sépare les éléments par des espaces, jamais par des deux-points.
set -gx PATH $PATH /opt/outils/binCréer des fonctions et les rendre persistantes
Section intitulée « Créer des fonctions et les rendre persistantes »Les fonctions regroupent plusieurs commandes sous un même nom. En Fish, elles remplacent avantageusement les alias, car elles acceptent des arguments et de la logique. Les arguments arrivent dans la liste $argv, indexée à partir de 1 et non de 0.
function salut echo "Salut, $argv[1] ! Comment vas-tu ?"end
salut AliceSalut, Alice ! Comment vas-tu ?Une fonction définie au clavier disparaît avec la session. Pour la conserver, funcsave l'écrit sur disque dans ~/.config/fish/functions/, où Fish la rechargera automatiquement dans tous vos futurs terminaux. C'est le seul mécanisme de persistance des fonctions : il n'existe pas de « fonction universelle » en Fish, contrairement aux variables que set -U sait rendre universelles.
funcsave salutfuncsave: wrote /root/.config/fish/functions/salut.fishLes alias suivent exactement le même chemin : alias fabrique en réalité une fonction, que funcsave sait donc enregistrer.
alias ll="ls -la"funcsave llPour relire une fonction, appelez functions avec son nom : la commande affiche son code source, description comprise. C'est aussi la façon de vérifier ce que fait une fonction héritée d'un plugin.
function addition --description "Ajoute deux nombres" math $argv[1] + $argv[2]end
functions addition# Defined interactivelyfunction addition --description 'Ajoute deux nombres' math $argv[1] + $argv[2];endDéboguer une fonction
Section intitulée « Déboguer une fonction »Quand une fonction ne fait pas ce que vous attendez, vous voulez voir chaque commande réellement exécutée. Fish fournit pour cela la variable fish_trace : dès qu'elle vaut 1, le shell affiche les commandes au fur et à mesure, préfixées par > pour l'appel et --> pour les commandes internes.
set fish_trace 1addition 2 3set -e fish_trace> addition 2 3--> math 2 + 35Pensez bien à désactiver la trace avec set -e fish_trace une fois le diagnostic terminé, sinon votre terminal reste bavard. Pour les problèmes qui touchent le shell lui-même plutôt qu'une de vos fonctions, fish --debug=<catégorie> active les journaux internes, par exemple fish --debug=complete pour instrumenter la complétion.
Réagir à un événement
Section intitulée « Réagir à un événement »Fish peut déclencher une fonction quand un événement survient, grâce à l'option --on-event. Les événements réellement émis par le shell sont peu nombreux et portent des noms précis : fish_prompt (avant chaque affichage de l'invite), fish_preexec et fish_postexec (juste avant et juste après l'exécution d'une commande), fish_exit (à la fermeture du shell) ou encore fish_command_not_found.
function au_revoir --on-event fish_exit echo "Session terminée."endLe piège est que Fish accepte n'importe quel nom d'événement sans broncher, y compris un nom qui n'existe pas. La fonction est alors bien enregistrée, visible dans functions --handlers, mais elle ne se déclenchera jamais, et aucun message d'erreur ne vous préviendra. Un --on-event session-start, par exemple, ne produit strictement rien, car Fish n'émet aucun événement de ce nom.
Pour exécuter du code au démarrage d'un shell, n'inventez donc pas d'événement : placez simplement vos commandes dans config.fish, qui est lu à chaque ouverture de session.
Variables et portées
Section intitulée « Variables et portées »Fish n'a pas de mot-clé export : tout passe par la commande set, dont une option détermine la portée. C'est plus explicite que Bash, à condition de connaître les trois portées et de choisir la bonne, faute de quoi vos réglages disparaissent au prochain terminal.
| Portée | Option | Durée de vie |
|---|---|---|
| Locale (défaut dans un bloc) | set -l | Le bloc ou la fonction en cours |
| Globale | set -g | La session en cours |
| Universelle | set -U | Toutes les sessions, persistée sur disque |
| Exportée aux sous-processus | -x (combinable) | Selon la portée choisie |
La portée universelle est la spécificité de Fish : set -Ux EDITOR vim est immédiatement visible dans tous vos terminaux ouverts, sans toucher au moindre fichier de configuration. C'est le bon réflexe pour une préférence personnelle stable.
set -Ux EDITOR vimVérification : set -S affiche la portée réelle d'une variable, ce qui lève tout doute.
set -S EDITORPour supprimer une variable, quelle que soit sa portée, utilisez set -e suivi de son nom.
set -e EDITORLes raccourcis clavier de Fish
Section intitulée « Les raccourcis clavier de Fish »Fish est confortable surtout parce que ses raccourcis sont déjà en place. Le tableau ci-dessous ne liste que des liaisons vérifiées avec la commande bind sur Fish 4.0.2 : c'est votre source de vérité, et vous pouvez la relancer à tout moment pour inspecter votre propre configuration.
| Raccourci | Action réelle |
|---|---|
→ ou Ctrl + F | Accepte l'autosuggestion affichée en gris |
Tab | Ouvre la complétion |
Ctrl + R | Recherche dans l'historique (pageur interactif) |
Ctrl + A / Ctrl + E | Début / fin de ligne |
Ctrl + U / Ctrl + K | Efface avant / après le curseur |
Ctrl + W | Efface le composant de chemin précédent |
Ctrl + D | Efface le caractère, ou quitte si la ligne est vide |
Alt + ← / Alt + → | Ligne vide : répertoire précédent / suivant. Sinon : mot par mot |
Alt + ↑ / Alt + ↓ | Recherche dans l'historique le token sous le curseur |
Alt + . | Insère le dernier argument de la commande précédente |
Alt + D | Ligne vide : affiche l'historique des répertoires. Sinon : efface le mot suivant |
Ctrl + S | Active la recherche dans le pageur de complétion |
Deux liaisons méritent une lecture attentive, car elles changent de comportement selon le contexte. Alt + ← et Alt + → naviguent dans l'historique des répertoires uniquement quand la ligne de commande est vide ; dès que vous avez tapé quelque chose, elles déplacent le curseur mot par mot. Les commandes équivalentes sont prevd et nextd, et dirh affiche la pile complète.
cd /tmp/projetcd /var/logprevdpwd/tmp/projetVous pouvez évidemment définir vos propres liaisons avec bind, en utilisant les noms de touches de Fish 4 (ctrl-t, alt-p). L'ancienne notation à échappement (\ct) reste acceptée, mais les noms lisibles sont plus faciles à relire dans un config.fish.
bind ctrl-t 'date'Vérification : bind | grep ctrl-t doit afficher votre liaison. Ajoutez la ligne à config.fish pour la conserver.
Étendre Fish avec Fisher
Section intitulée « Étendre Fish avec Fisher »Fisher est le gestionnaire de plugins le plus utilisé de l'écosystème Fish. Son installation officielle propose un curl | source, c'est-à-dire l'exécution directe de code téléchargé : ne faites jamais cela. Vous exécuteriez dans votre shell un fichier que vous n'avez pas lu, servi par un serveur distant, sans aucune vérification. Téléchargez, relisez, puis chargez.
-
Téléchargez la fonction Fisher dans un fichier local :
Fenêtre de terminal curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish -o fisher.fish -
Relisez le fichier avant toute exécution. Vous devez y voir du code Fish lisible, commençant par
function fisher:Fenêtre de terminal less fisher.fish -
Chargez-le dans la session, puis laissez Fisher s'installer lui-même :
Fenêtre de terminal source fisher.fish && fisher install jorgebucaran/fisher
Une fois Fisher en place, l'installation d'un plugin tient en une commande. Les plugins vivent dans votre configuration utilisateur, sans privilège root.
fisher install jorgebucaran/nvm.fishfisher listPour retirer un plugin, fisher remove suivi de son nom suffit. Le catalogue communautaire est publié sur awsm.fish.
Fish et les scripts : ne pas confondre
Section intitulée « Fish et les scripts : ne pas confondre »Fish n'est pas compatible POSIX, et c'est assumé. Un script Bash collé dans un terminal Fish échouera dès la première boucle ou le premier [[ ... ]]. La règle est simple : Fish pour l'interactif : Bash pour les scripts. Vos scripts existants s'exécutent normalement en les appelant explicitement, puisqu'ils déclarent leur propre interpréteur.
bash ./deploiement.shUne idée reçue mérite d'être corrigée : on lit souvent que Fish ignore la syntaxe $(...). C'était vrai autrefois, mais Fish la prend en charge depuis la version 3.4 (2022). Les deux formes de substitution de commande fonctionnent donc, la forme historique entre parenthèses seules et la forme compatible Bash.
echo "Nous sommes le (date +%d/%m)"echo "Nous sommes le $(date +%d/%m)"Restent les vraies divergences : set remplace export, les listes remplacent les tableaux, et les blocs se ferment par end plutôt que par fi ou done.
Dépannage
Section intitulée « Dépannage »Voici les blocages les plus courants lors d'un passage à Fish, avec la cause et la correction directement applicable.
| Symptôme | Cause probable | Solution |
|---|---|---|
chsh: PAM: Authentication failure | Mot de passe erroné, ou Fish absent de /etc/shells | Vérifier avec grep fish /etc/shells et ajouter le chemin : command -v fish | sudo tee -a /etc/shells |
Le PATH contient des doublons qui se multiplient | set -gx PATH $PATH:/chemin (produit cartésien) | Repartir de fish_add_path /chemin, ou séparer par des espaces |
Un chemin ajouté n'apparaît pas dans $PATH | Le répertoire n'existe pas : fish_add_path l'ignore en silence | test -d /chemin; echo $status doit renvoyer 0 |
| Une fonction supprimée réapparaît au prochain terminal | functions -e n'efface que la session ; le fichier reste | rm ~/.config/fish/functions/<nom>.fish |
Une fonction --on-event ne se déclenche jamais | Nom d'événement inexistant, accepté sans erreur | Utiliser un événement réel (fish_prompt, fish_exit) ou passer par config.fish |
| Les scripts Bash échouent dans Fish | Fish n'est pas compatible POSIX | Les lancer explicitement : bash script.sh |
fish_config n'ouvre pas de navigateur | Session SSH sans interface graphique | Utiliser fish_config prompt list puis choose et save |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Fish est confortable sans configuration : autosuggestions, coloration et complétion sont actives dès l'installation.
- Essayez Fish en le lançant comme une commande avant de faire un
chshqui engage votre shell de connexion. - Le
PATHne s'étend pas avec::set -gx PATH $PATH:/cheminproduit un produit cartésien qui double lePATHà chaque rechargement. Utilisezfish_add_path. - Les fonctions universelles n'existent pas : seules les variables peuvent être universelles (
set -U). Une fonction se persiste avecfuncsave, dans~/.config/fish/functions/. functions -en'efface que la session : supprimez aussi le fichier pour une suppression durable.- Déboguez avec
set fish_trace 1, et non avec une option--tracequi n'existe pas. $(...)fonctionne depuis Fish 3.4 : la substitution de commande à la Bash est prise en charge.- Fish pour l'interactif, Bash pour les scripts : la portabilité de vos automatisations n'est pas négociable.
Un peu d'histoire
Section intitulée « Un peu d'histoire »Fish naît en 2005, à une époque où Bash et Zsh dominent sans partage et exigent de longues configurations pour devenir ergonomiques. Son pari : s'affranchir des conventions Unix quand elles nuisent à l'utilisateur, plutôt que de les perpétuer par tradition. Ce choix lui vaut son incompatibilité POSIX, mais aussi son confort immédiat.
Les jalons marquants de son évolution éclairent ce que vous utilisez aujourd'hui :
- 2009 : arrivée de l'interface web de configuration (
fish_config). - 2013 : Fish 2.0 améliore les scripts et les raccourcis clavier.
- 2016 : le gestionnaire de plugins Fisher s'impose dans l'écosystème.
- 2022 : Fish 3.4 ajoute la substitution de commande
$(...), qui rapproche la syntaxe de Bash. - 2025 : Fish 4.0 est entièrement réécrit en Rust, après vingt ans de C++. Le comportement ne change pas pour l'utilisateur, mais la base de code gagne en sûreté mémoire et en maintenabilité. C'est la branche livrée par Debian 13 en version 4.0.2.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- tmux : multiplexeur de terminal : Garder vos sessions actives après déconnexion, quel que soit le shell utilisé.
- Documentation officielle de Fish : La référence complète des builtins, des événements et des liaisons clavier.
- Catalogue awsm.fish : Les plugins et thèmes maintenus par la communauté.