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_configopens 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.