Probabilmente hai passato ore a sistemare .zshrc o .bashrc, a installare Oh My Zsh, a cercare il plugin giusto per avere l’autocompletamento che funziona, i colori nella sintassi, i suggerimenti dal tuo storico dei comandi. Tutto questo lavoro esiste perché Bash e Zsh, da soli, non ti danno quasi niente di moderno — sono potenti, diffusissimi, ma partono spogli.
Fish, che sta per Friendly Interactive Shell, nasce da una premessa opposta: tutto quello che ti aspetti da una shell moderna deve funzionare subito, senza installare nulla di extra. Con la versione 4.0, il progetto ha compiuto un salto notevole — l’intero codebase è stato riscritto da zero in Rust, abbandonando il C++ su cui si reggeva da vent’anni.
Oggi, con la verisone 4.7.1 rilasciata il 7 maggio 2026, Fish è uno strumento maturo, veloce e sorprendentemente piacevole da usare ogni giorno. Se usi il terminale spesso — per sviluppare, per gestire server, per automatizzare compiti di sistema — vale la pena capire perché in molti stanno facendo questo cambio.
Cosa ottieni subito, senza configurare nulla
La differenza più immediata rispetto a Bash o Zsh è semplice: Fish ti mostra i suggerimenti mentre digiti, evidenzia la sintassi in tempo reale e completa automaticamente i comandi basandosi sulla tua cronologia e sui file presenti nella directory corrente. Tutto questo accade al primo avvio, senza toccare nessun file di configurazione.
Prendiamo l’autocompletamento. In Bash, per ottenere qualcosa di simile devi installare il pacchetto bash-completion e sperare che il tuo sistema lo abbia già configurato. In Zsh, devi attivare il modulo compinit nel tuo .zshrc e spesso integrarlo con Oh My Zsh per avere risultati decenti. Fish invece ha completamenti specifici per centinaia di comandi già integrati, aggiornati regolarmente. Quando digiti git e premi Tab, ottieni una lista di sottocomandi con una breve descrizione per ciascuno, senza installare nulla.
L’evidenziazione della sintassi funziona così: mentre scrivi un comando, Fish lo colora progressivamente. Il nome del comando diventa verde se è valido ed eseguibile, rosso se non lo trova nel PATH. I percorsi ai file vengono sottolineati se il file esiste, rimangono normali se non è ancora stato creato. Questo elimina un’intera categoria di errori stupidi, come il typo nel nome del comando o il percorso sbagliato, prima ancora di premere Invio.

C’è anche il pannello di configurazione web, attivabile con il comando fish_config. Apre un’interfaccia browser da localhost da cui puoi cambiare tema, colori e prompt senza scrivere una riga di codice.
Come installarlo su Linux, macOS e Windows
Per Ubuntu e Debian, i repository ufficiali di Fish mantengono sempre l’ultima versione stabile. I repository standard di Ubuntu tendono a restare indietro (spesso ancora sulla 3.x), quindi conviene usare il PPA ufficiale:
sudo apt-add-repository ppa:fish-shell/release-4
sudo apt update
sudo apt install fishSu Arch Linux e derivate come Manjaro, Fish è già nei repo ufficiali:
sudo pacman -S fish
Su Fedora:
sudo dnf install fish
Su macOS, il modo più comodo è Homebrew:
brew install fish
Su Windows, Fish non ha ancora un supporto nativo completo, ma funziona bene all’interno di WSL2 (Windows Subsystem for Linux). Una volta installata la distribuzione Linux preferita su WSL, segui il metodo corrispondente.
Dopo l’installazione, puoi avviare Fish semplicemente digitando fish dal tuo terminale. Per impostarlo come shell predefinita, prima aggiungi il percorso alla lista delle shell valide, poi cambia la shell per il tuo account:
# Aggiungi fish alla lista delle shell autorizzate
echo /usr/bin/fish | sudo tee -a /etc/shells
# Imposta fish come shell predefinita
chsh -s /usr/bin/fish
Se non sei sicuro del percorso di installazione, which fish te lo restituisce in un attimo.
Il sistema delle abbreviazioni: più potente degli alias
Uno dei meccanismi più sottovalutati di Fish è quello delle abbreviazioni, che funzionano in modo diverso rispetto agli alias tradizionali.
Quando definisci un alias in Bash, il sistema sostituisce la parola a ogni esecuzione in modo trasparente. Il comando che appare nel terminale è l’alias breve, non il comando reale. Questo crea problemi quando condividi comandi con altri o vuoi rileggere la tua cronologia, perché vedi gst invece di git status e devi ricordarti mentalmente la corrispondenza.
Le abbreviazioni di Fish funzionano al contrario: quando digiti gst e premi Spazio o Invio, il testo viene espanso visivamente nella riga di comando in git status prima dell’esecuzione. Hai tutta la velocità di digitare un’abbreviazione corta, ma la riga di comando mostra sempre il comando completo. La cronologia registra git status, non gst. La leggibilità è preservata.
Per aggiungere abbreviazioni, il posto giusto è il file ~/.config/fish/config.fish oppure un file separato in ~/.config/fish/conf.d/. Questo secondo approccio è più pulito perché divide per categoria:
# ~/.config/fish/conf.d/git.fish
abbr -a gs "git status"
abbr -a gco "git checkout"
abbr -a gp "git push"
abbr -a gl "git log --oneline --graph --decorate"
abbr -a gd "git diff"
abbr -a ga "git add"
abbr -a gcm "git commit -m"
Puoi anche aggiungere abbreviazioni che si espandono solo dopo un comando specifico, tramite --command. Ad esempio, se vuoi che --no-cache si espanda automaticamente ma solo dopo docker build:
abbr --add no-cache --command "docker build" -- "--no-cache"
Per vedere tutte le abbreviazioni attive, digita abbr senza argomenti. Per rimuoverne una, usa abbr --erase nome.
Funzioni e variabili: la sintassi di Fish
Fish non è compatibile con POSIX, il che significa che la sintassi per scrivere script è diversa da Bash e Zsh. Questo all’inizio può sembrare uno svantaggio, ma nella pratica la sintassi di Fish è molto più leggibile e prevedibile.
Definire una funzione è diretto:
function mkcd
mkdir -p $argv[1]
cd $argv[1]
end
Puoi salvarla permanentemente con funcsave mkcd, che la scrive in ~/.config/fish/functions/mkcd.fish. Da quel momento, la funzione è disponibile a ogni avvio senza dover fare source di nessun file.
Per le variabili, Fish usa set con degli scope espliciti. Questo elimina l’ambiguità tipica di Bash, dove non è sempre chiaro dove finisce una variabile:
set -l variabile_locale "solo in questa funzione"
set -g variabile_globale "disponibile in tutta la sessione"
set -Ux VARIABILE_UNIVERSALE "persiste tra sessioni, anche dopo riavvio"
Le variabili universali (-U) sono forse la funzione più comoda di tutto Fish. Vengono scritte su disco in ~/.config/fish/fish_variables e restano disponibili in tutte le finestre del terminale e nelle sessioni future, senza bisogno di esportarle nel .bashrc.
Per aggiungere un percorso al PATH in modo permanente, basta questo:
fish_add_path /home/tuo-utente/.local/bin
Il comando è intelligente, perché controlla che il percorso non sia già presente prima di aggiungerlo. Non accumula duplicati nel PATH anche se lo chiami più volte.
Con Fish 4.1 è arrivata anche la sintassi { ... } per i blocchi compatti, che sostituisce la forma verbosa begin; ...; end. Questo rende molto più leggibili i one-liner complessi:
# Prima (ancora valido)
echo "start"; begin; echo "dentro"; end; echo "fine"
# Con Fish 4.1+ (più compatto)
echo "start"; { echo "dentro" }; echo "fine"
La sintassi delle condizioni, dei cicli e delle variabili di Fish è diversa da Bash. Ma diversa non significa più difficile. La documentazione ufficiale su fishshell.com/docs è tra le migliori che esistano nel mondo open source — chiara, ricca di esempi, aggiornata a ogni release.
Plugin con Fisher: quando Fish da solo non basta
Fish funziona già molto bene senza plugin, ma ci sono scenari in cui l’ecosistema di estensioni torna decisamente utile. Il gestore di plugin più diffuso si chiama Fisher, ed è progettato per essere leggero: installa i plugin direttamente come funzioni Fish, senza dipendenze esterne.
Per installare Fisher:
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher
Tra i plugin più utili troviamo i seguenti.
- fzf.fish. Aggiunge la ricerca fuzzy interattiva a Fish. Con
Ctrl+Rottieni una finestra di ricerca nella cronologia dei comandi molto più potente di quella predefinita. ConCtrl+Alt+Fpuoi cercare file nella directory corrente e inserirne il percorso direttamente nella riga di comando. Richiedefzfinstallato nel sistema (brew install fzfsu macOS,sudo apt install fzfsu Linux).
fisher install PatrickF1/fzf.fish
- nvm.fish. È la versione Fish-nativa del celebre Node Version Manager. Il nvm originale è scritto in Bash e non funziona direttamente in Fish. Questo wrapper lo rende completamente compatibile.
fisher install jorgebucaran/nvm.fish
nvm install lts
set --universal nvm_default_version lts
- Tide. È un prompt alternativo a quello predefinito di Fish, ispirato a Powerlevel10k di Zsh. È asincrono, quindi non rallenta la shell mentre carica le informazioni di Git, e mostra lo stato del repository, la versione del linguaggio in uso (Node, Python, Go…) e altre informazioni contestuali.
fisher install IlanCosman/tide@v6
La riscrittura in Rust
Con Fish 4.0, l’intero codebase è stato portato da C++ a Rust. Per chi usa Fish ogni giorno, il cambiamento non è visibile a prima vista: Fish era già veloce, e continua a esserlo. Ma ci sono dei miglioramenti che nel tempo si fanno sentire.
Il più rilevante riguarda la stabilità a lungo termine. Il vecchio codice C++ aveva qualche problema con i memory leak durante sessioni molto lunghe. Ora questi problemi non si ripresentano. Il sistema di ownership e borrow checking di Rust elimina questa categoria di errori alla radice, senza bisogno di interventi manuali.
C’è poi un vantaggio pratico per chi compila dal sorgente o vuole contribuire al progetto. Il compilatore Rust fornisce messaggi di errore molto più chiari di g++, e l’ecosistema Cargo semplifica la gestione delle dipendenze. Il progetto è diventato più facile da mantenere e da far crescere.
Dal lato funzionale, la serie 4.x ha introdotto miglioramenti all’autocompletamento multilinea, alla gestione delle variabili universali (ora spostate dalla memoria volatile a file di configurazione espliciti), ai temi via fish_config theme choose e al supporto vi/vim nella modalità di input tramite fish_vi_key_bindings. La versione 4.7 è la più stabile e rifinita della serie.
Fish e gli script Bash
Abbiamo già detto che Fish non è POSIX-compatibile. Questo significa che gli script Bash che trovi in rete non girano direttamente in Fish. Il punto di equilibrio che funziona bene in pratica è usare Fish come shell interattiva personale, tenendo Bash (o sh) per gli script. Fish, di default, usa #!/usr/bin/env fish solo per i file .fish. Qualsiasi script con shebang #!/bin/bash viene eseguito correttamente da Bash, indipendentemente da quale sia la shell predefinita. I due mondi coesistono senza problemi.
Fish shell: conclusione
Fish è la shell con il miglior rapporto qualità/sforzo che conosca. Zsh con la configurazione giusta fa cose notevoli, e Nushell (già trattato su questo blog) ha una filosofia interessante sui dati strutturati. Il punto è che Fish ti dà il 90% dei vantaggi di una shell moderna senza investire ore a configurarla.
Se passi molto tempo nel terminale e oggi usi Bash, il cambio è quasi privo di rischi. Fish convive tranquillamente con Bash sul sistema, puoi provarla senza impegno semplicemente digitando fish nel tuo terminale, e tornare indietro è immediato.
Se usi Zsh e sei soddisfatto, il cambio è meno urgente. Ma se ti accorgi di passare più tempo a gestire la configurazione che a lavorare, Fish è una risposta convincente a quel problema.
La riscrittura in Rust e la cadenza di release regolare degli ultimi diciotto mesi mostrano un progetto in ottima salute. Con 4.7.1 come punto di partenza, Fish è probabilmente nello stato migliore in cui sia mai stato.













