Skip to main content

Fish Shell: An Interactive Shell That Works Out of the Box

·543 words·3 mins
[Your Name]
Author
[Your Name]
Capturing light with Sony A7R2, building workflows with NixOS & Emacs, exploring LLMs and Agents.
Table of Contents
NixOS Toolchain - This article is part of a series.
Part 3: This Article

The first time you use Fish, you’ll wonder why other shells don’t even ship with autocomplete by default.

Fish (Friendly Interactive Shell) is a shell designed for interactive use. It comes with syntax highlighting, autosuggestions, and fuzzy search built-in—no need to install Oh-My-Zsh and dozens of plugins like with Zsh.

Installation
#

NixOS:

users.defaultUserShell = pkgs.fish;
programs.fish.enable = true;

Or via Home Manager:

programs.fish = {
  enable = true;
  interactiveShellInit = ''
    set -g fish_greeting
  '';
};

Why Switch from Zsh to Fish
#

FeatureZsh (default)Fish (default)
Syntax highlighting❌ Needs plugin✅ Built-in
Autosuggestions❌ Needs plugin✅ Built-in
Fuzzy completion❌ Needs plugin✅ Built-in
Man page completion✅ Auto-generated
Config syntaxBash compatibleClean and intuitive
Startup speedSlow (many plugins)Fast

Fish’s philosophy is “the default should be the best.”

Daily Usage
#

Autosuggestions
#

As you type, Fish shows suggestions in grey based on history and context:

$ git comm
         ↑ grey text: "git commit -m "
         → Press → or Ctrl+F to accept

Tab Completion
#

Press Tab to list all options, with fuzzy matching:

$ cd pro<Tab>
projects/  proposals/  prometheus/

Syntax Highlighting
#

Valid commands are green, invalid ones red. Existing paths are blue, non-existent ones have red underlines:

$ ech hello      # "ech" in red (command not found)
$ cat /tmp/test  # "/tmp/test" underlined red (file doesn't exist)

Configuration
#

Fish config lives in ~/.config/fish/:

~/.config/fish/
├── config.fish      # Main config
├── conf.d/          # Auto-loaded scripts
│   ├── abbr.fish
│   ├── aliases.fish
│   └── path.fish
└── functions/       # Custom functions

My config.fish
#

# Remove greeting
set -g fish_greeting

# Environment variables
set -gx EDITOR emacsclient -c
set -gx VISUAL emacsclient -c
set -gx LANG en_US.UTF-8

# PATH
fish_add_path ~/.cargo/bin
fish_add_path ~/.local/bin
fish_add_path /nix/var/nix/profiles/default/bin

Abbreviations vs Aliases
#

Fish recommends abbr over alias because abbreviations expand as you type, so you can see the actual command:

abbr -a g git
abbr -a ga 'git add'
abbr -a gc 'git commit'
abbr -a gp 'git push'
abbr -a gs 'git status'
abbr -a l 'ls -la'
abbr -a .. 'cd ..'
abbr -a ... 'cd ../..'

Effect: Type gs, press space, it auto-expands to git status.

Custom Functions
#

# ~/.config/fish/functions/ll.fish
function ll
    ls -lah $argv
end
# ~/.config/fish/functions/mkcd.fish
function mkcd
    mkdir -p $argv[1]
    cd $argv[1]
end

NixOS-specific Tips
#

Auto-detect nix-shell
#

# config.fish
if test -n "$IN_NIX_SHELL"
    set -g fish_greeting "📦 nix-shell"
end

direnv + nix-direnv
#

# home.nix
programs.direnv = {
  enable = true;
  nix-direnv.enable = true;
};

Automatically loads dev environment when entering a directory with .envrc, unloads when leaving.

Bash Incompatibility Notes
#

Fish syntax differs from Bash. For scripts, it’s recommended to:

  1. Use #!/usr/bin/env bash in script shebangs — keep writing scripts in Bash
  2. Use Fish only for interactive use — don’t write scripts in Fish
  3. When copy-pasting Bash commands from the web — most simple commands work, complex pipes may need tweaking

Summary
#

If you’re tired of configuring Zsh, Fish is the most hassle-free choice. It won’t turn you into a “shell config expert,” but it will make you slightly happier every time you open a terminal.


The NixOS Toolchain series wraps up here for now. Next up might be some specific Nix configuration tips.

NixOS Toolchain - This article is part of a series.
Part 3: This Article