fish (the “friendly interactive shell”) gives you autosuggestions, syntax highlighting and rich tab completion out of the box, without plugins or long config files. It isn’t POSIX-compatible, though, so some bash habits need adjusting. Here’s how to set it up on a Linux server, and what’s different.

Comparison: sh vs bash vs zsh vs fish.

Install

sudo apt install fish            # Debian/Ubuntu (a PPA offers newer versions)
sudo dnf install fish            # RHEL family (EPEL) / Fedora
fish --version

Try it without changing anything: just type fish. Type exit to return.

Make it your default shell (for your own user):

chsh -s "$(command -v fish)"

What you get immediately

  • Autosuggestions from history and paths. Press → (or Ctrl+F) to accept, Alt+→ to accept one word.
  • Syntax highlighting: invalid commands turn red before you press Enter.
  • Tab completion generated from man pages, with descriptions.
  • History search: type part of a command, then press ↑.
  • Web configuration: fish_config opens a browser UI for colours and prompts (on a server, use its terminal options, or edit files).

Configuration

Settings live in ~/.config/fish/config.fish:

# environment variables
set -gx EDITOR vim
set -gx LANG C.UTF-8

# add to PATH (persists, no duplicates)
fish_add_path ~/.local/bin /usr/local/go/bin

if status is-interactive
    abbr -a gs git status
    abbr -a k kubectl
    abbr -a dps 'docker ps --format "table {{.Names}}\t{{.Status}}"'
end

Abbreviations expand when you press Space, so you see (and history records) the full command. That makes them clearer than aliases.

Functions instead of aliases

function mkcd
    mkdir -p $argv[1]; and cd $argv[1]
end
funcsave mkcd          # saves to ~/.config/fish/functions/mkcd.fish

Syntax differences from bash

bash fish
VAR=value set VAR value
export VAR=value set -gx VAR value (export also works)
$(command) (command) (or $(command) in fish 3.4+)
cmd1 && cmd2 cmd1; and cmd2 (or && in fish 3.0+)
if [ … ]; then … fi if test …; … end
for i in 1 2 3; do … done for i in 1 2 3; … end
$1, $@ $argv[1], $argv
source ~/.bashrc Not compatible: port settings to config.fish
Here-documents <<EOF Not supported (use printf or echo)

Running bash snippets: copy-pasted installation commands mostly work. For anything bash-specific, run it in bash: bash -c '…', or put it in a script with #!/bin/bash.

Plugins (optional)

Fisher is a lightweight plugin manager:

curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher
fisher install jethrokuan/z         # directory jumping

Starship is a fast cross-shell prompt that works well with fish (starship init fish | source in config.fish).

Server advice

  • Use fish for your own interactive account. Keep root on bash, and keep scripts in bash or POSIX sh.
  • Cron and systemd don’t use your login shell, so fish doesn’t affect scheduled jobs. See cron environment variables.
  • Tools that write to ~/.bashrc (nvm, pyenv, conda installers) need fish-specific setup. Check each tool’s docs for fish support.

Quick reference

Task Command
Install sudo apt install fish
Default shell chsh -s $(command -v fish)
Config ~/.config/fish/config.fish
Set variable set -gx VAR value
Add to PATH fish_add_path dir
Abbreviation abbr -a name 'command'

Related: zsh and Oh My Zsh and Linux terminal shortcuts.

  • Linux
  • Shell
  • Productivity