Andrew Mercer
on this page

The friendly interactive shell dates from 2005. It deliberately drops POSIX compatibility in favour of a cleaner syntax and good defaults: autosuggestions from history, syntax highlighting, and completions generated from man pages all work out of the box, with no plugins. fish 4.0 (early 2025) was a full rewrite from C++ to Rust, and the 4.x series continues from there.

Syntax compared with bash

bash fish
VAR=value set VAR value
export VAR=value set -gx VAR value (export VAR=value also works)
$? $status
$(cmd) (cmd) or $(cmd)
if [ -f x ]; then ...; fi if test -f x; ...; end
for f in *; do ...; done for f in *; ...; end
func() { ...; } function func; ...; end
$1, $@ $argv[1], $argv
cmd1 && cmd2 cmd1 && cmd2 (or cmd1; and cmd2)
alias ll='ls -l' in .bashrc abbr -a ll ls -l (expands as you type)

Every variable is a list, and variables are never word-split, so the quoting problems that dominate bash scripting mostly disappear.

Configuration

~/.config/fish/config.fish                 # runs for every fish; wrap interactive-only bits in: if status is-interactive
~/.config/fish/conf.d/*.fish               # snippets sourced before config.fish
~/.config/fish/functions/name.fish         # one function per file, autoloaded on first use

fish_add_path ~/.cargo/bin                 # add to PATH once, persistently, without duplicates
set -U EDITOR vim                          # universal variable: shared by all sessions, survives restarts
funcsave mkcd                              # save a function defined at the prompt to functions/
fish_config                                # browser-based UI for colours, prompts, and bindings

Fisher is the usual plugin manager.

Caveats

fish can't run bash scripts or source bash files. Run them with bash script.sh, and keep every script's shebang pointing at sh or bash. Tools that print export VAR=... lines for you to eval (ssh-agent, many version managers, cloud CLIs) usually have a fish mode, such as ssh-agent -c or a --shell fish flag. If one doesn't, the bass plugin can import a bash script's environment changes.

Some people prefer to launch fish from their terminal emulator instead of making it their login shell, so login sessions, SSH, and system tools that assume a POSIX login shell keep working. Setting it with chsh works too; just check that $PATH is still complete afterwards.

Further reading