fish & Shell

fish for beginners: suggestions, aliases and configuration

Keep your shell settings local

These settings and command history are stored locally. Programs you run can be online. Avoid credentials in command lines or publicly shared configuration files.

In this article
  1. Understand what fish changes
  2. Try a session before changing your login shell
  3. Use suggestions and Tab completion
  4. Distinguish aliases from abbreviations
  5. Keep config.fish small
  6. Understand variables and existing scripts
  7. Clean up and diagnose errors
  8. History, privacy and references

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.

References checked on 8 October 2026. Exercise names are deliberately separate from your regular shortcuts.