In this article
fish makes the command line approachable: it suggests earlier commands and completes many options. On Cthulhu, my NixOS configuration enables fish and selects it as nebu's shell. My Fastfetch screenshot shows this combination too.
The repository contains that NixOS system configuration, but no separately published personal config.fish. This article therefore uses newly written exercises rather than presenting a nonexistent personal shell file.
Understand what fish changes
Kitty or another terminal supplies the window. fish interprets commands, expands variables and launches programs inside it. A terminal theme is consequently separate from a fish function or prompt.
fish has its own syntax and is not completely interchangeable with Bash or a POSIX shell. An existing script starting with #!/bin/bash still runs through Bash. Individual Bash lines pasted into fish may follow different rules, especially variable assignments and multiline control structures.
Check that fish is installed:
fish --version
Try a session before changing your login shell
Start an additional shell:
fish
Use exit to return to the previous shell. These exercises do not require changing your login shell. A single test session is easier to understand than changing the terminal, prompt and account configuration together.
My NixOS file provides this connection:
programs.fish.enable = true;
users.users.nebu.shell = pkgs.fish;
This is an excerpt inside a NixOS module, not a complete file. Other distributions use their own account-management mechanisms. On NixOS, change a declaratively managed shell in the configuration; the NixOS introduction explains that structure.
Use suggestions and Tab completion
Run a harmless command in the fish test session:
ls -lah
Start typing it again afterwards. A faint history suggestion may appear; the right arrow accepts it, and Enter executes the resulting line. Displaying a suggestion does not itself launch a program. Tab completes available files, commands and supported options.
An earlier successful command is not automatically appropriate now. A different working directory or changed filename may alter its effect. Read the complete expanded line before pressing Enter, especially for commands that write or delete data.
Distinguish aliases from abbreviations
In fish, an alias is a conveniently created function. Choose a new exercise name rather than replace a standard function:
alias lltutorial 'ls -lah'
Try it:
lltutorial
The function accepts additional arguments. Inspect its definition:
functions lltutorial
An abbreviation instead expands typed text. Create one for the exercise:
abbr --add gsttutorial 'git status --short'
Type gsttutorial followed by a space. The line should expand to git status --short, keeping the eventual command visible. Outside a Git working tree, that command appropriately reports that no repository exists there.
Keep config.fish small
fish normally reads ~/.config/fish/config.fish; a different XDG_CONFIG_HOME changes that location. Back up an existing file before editing it. This original snippet is enough to begin:
if status is-interactive
abbr --add gsttutorial 'git status --short'
end
status is-interactive limits the setting to interactive sessions. It helps avoid unsolicited terminal output in automatically launched shells. funcsave can persist a function in its own file; check the name first because an existing function file can be overwritten.
For the exercise alias:
funcsave lltutorial
This optional step writes a local function file. A new fish session can then autoload the function. Keeping small functions separate makes their origin easier to identify later.
Understand variables and existing scripts
fish sets variables with set, for example within an exercise session or function:
set -l tutorial_message 'Hello from fish'
Display its value:
echo $tutorial_message
-l means local to the current scope; it does not create a persistent universal setting. Environment variables passed to child programs also need export. Do not treat Bash's export NAME=... as a universal model for every fish configuration; use the documented fish syntax and the intended scope.
Run an unchanged Bash script explicitly with Bash when needed. Replacing its interpreter with fish is not a port. A script's shebang describes a real dependency.
Clean up and diagnose errors
Remove the abbreviation from the current session:
abbr --erase gsttutorial
Remove the function from memory:
functions --erase lltutorial
If you used funcsave, also remove the exercise's lltutorial.fish file from the fish functions directory and the exercise entry from config.fish. Otherwise, future sessions can load them again. Preserve your other functions while editing.
Check a configuration's syntax without executing it:
fish --no-execute ~/.config/fish/config.fish
A successful check confirms syntax, rather than the availability of every external program or the correct behaviour of every function.
History, privacy and references
Command history can include personal paths and commands. Enter passwords through a program's interactive prompt instead of placing them in command lines. Check configuration files for tokens and internal hostnames before publishing them.
- My checked NixOS configuration: enabling fish and selecting the user shell.
- Official fish tutorial.
- fish abbreviations.
- Saving functions and set.
References checked on 8 October 2026. Exercise names are deliberately separate from your regular shortcuts.