I just got a new MacBook and couldn't remember how to set up the fish shell the way I like ๐คท.
Below you can find my notes on setting it up from scratch on macOS.

Setup
Install fish
Run the following command to install fish using Homebrew:
brew install fish
Set fish as the default shell
Run the following command to add fish to the list of available shells and set it as the default shell:
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fishecho /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fishMake fish recognize Homebrew's binaries
Add the Homebrew's binaries to the list of fish known binaries (otherwise it won't run commands installed with brew) with the following command:
fish_add_path "/opt/homebrew/bin/"fish_add_path "/opt/homebrew/bin/"Create completition files
Parse manual pages installed on the system and attempt to create completion files in the fish configuration directory with the following command:
fish_update_completions
Customizations
Install fisher and fisher plugins:
- Install the
fisherplugin manager
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fishercurl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher- Install
zto quickly jump across known directories:
fisher install jethrokuan/zfisher install jethrokuan/z- Install
fzf, a CLI fuzzy-finder, and make it work amazingly well with fish:
brew install fzf && fisher install patrickf1/fzf.fishbrew install fzf && fisher install patrickf1/fzf.fish- Install a plugin that avoids issues where fish doesn't recognize global
npmscripts:
fisher install rstacruz/fish-npm-globalfisher install rstacruz/fish-npm-global- Install a fish-compatible version of
nvm:
fisher install jorgebucaran/nvm.fishfisher install jorgebucaran/nvm.fishChange the fish shell prompt (color/theme)
Add the following to ~/.config/fish/functions/fish_prompt.fish to change the fish theme:
function fish_prompt
set -l pointer_color red
test $status = 0; and set pointer_color yellow
set -q __fish_git_prompt_showupstream
or set -g __fish_git_prompt_showupstream auto
if not set -q VIRTUAL_ENV_DISABLE_PROMPT
set -g VIRTUAL_ENV_DISABLE_PROMPT true
end
set_color yellow
printf '%s' $USER
set_color normal
printf ' in '
set_color $fish_color_cwd
printf '%s' (prompt_pwd --dir-length=0)
set_color normal
# git
set_color white -d
set -l prompt_git (fish_git_prompt '%s')
test -n "$prompt_git"
and printf ' %s' $prompt_git
set_color normal
# Line 2
echo
set_color $pointer_color
printf 'ยป '
set_color normal
endfunction fish_prompt
set -l pointer_color red
test $status = 0; and set pointer_color yellow
set -q __fish_git_prompt_showupstream
or set -g __fish_git_prompt_showupstream auto
if not set -q VIRTUAL_ENV_DISABLE_PROMPT
set -g VIRTUAL_ENV_DISABLE_PROMPT true
end
set_color yellow
printf '%s' $USER
set_color normal
printf ' in '
set_color $fish_color_cwd
printf '%s' (prompt_pwd --dir-length=0)
set_color normal
# git
set_color white -d
set -l prompt_git (fish_git_prompt '%s')
test -n "$prompt_git"
and printf ' %s' $prompt_git
set_color normal
# Line 2
echo
set_color $pointer_color
printf 'ยป '
set_color normal
endAllow restarting the shell by running fish
Back in the day, with zsh I was used to restart the shell by running zsh. To do the same with fish, create a new funcion ~/.config/fish/functions/fish.fish:
# A way to reload the shell ร la "zsh"
function fish
source ~/.config/fish/config.fish
end# A way to reload the shell ร la "zsh"
function fish
source ~/.config/fish/config.fish
endPrint a new line in the CLI after any command
To print a new line after any command create a new function ~/.config/fish/functions/postexec_newline.fish:
# Print a new line after any command
# https://stackoverflow.com/a/70644608
function postexec_newline --on-event fish_postexec
echo
end# Print a new line after any command
# https://stackoverflow.com/a/70644608
function postexec_newline --on-event fish_postexec
echo
endTweak the config file
Here's my ~/.config/fish/config.fish file.
Protip: when running/customizing external programs in the config file it is a good practice to check if the program executable is available (with if type -q COMMAND_NAME) to avoid errors.
if status is-interactive
# Commands to run in interactive sessions can go here
end
# Disable the fish greeting message
set fish_greeting ""
# Print a new line after any command
source ~/.config/fish/functions/postexec_newline.fish
# Setup brew
eval "$(/opt/homebrew/bin/brew shellenv)"
# Clear line on CTRL + C
# Sometimes it still doesn't work well enough on node.js scripts :(
bind --preset \cC 'cancel-commandline'
# Auto-switch nvm version on cd
# Requires a ~/.node-version file with a valid node version
# https://github.com/jorgebucaran/nvm.fish/pull/186
if type -q nvm
function __nvm_auto --on-variable PWD
nvm use --silent 2>/dev/null # Comment out the silent flag for debugging
end
__nvm_auto
end
# Pyenv setup
# Requires `brew install pyenv`
if type -q pyenv
status --is-interactive; and source (pyenv init -|psub)
end
# `ls` โ `ls -laG` abbreviation
abbr -a -g ls ls -laG
# `ls` โ `exa` abbreviation
# Requires `brew install exa`
if type -q exa
abbr --add -g ls 'exa --long --classify --all --header --git --no-user --tree --level 1'
end
# `cat` โ `bat` abbreviation
# Requires `brew install bat`
if type -q bat
abbr --add -g cat 'bat'
end
# `rm` โ `trash` abbreviation (moves files to the trash instead of deleting them)
# Requires `brew install trash`
if type -q trash
abbr --add -g rm 'trash'
endif status is-interactive
# Commands to run in interactive sessions can go here
end
# Disable the fish greeting message
set fish_greeting ""
# Print a new line after any command
source ~/.config/fish/functions/postexec_newline.fish
# Setup brew
eval "$(/opt/homebrew/bin/brew shellenv)"
# Clear line on CTRL + C
# Sometimes it still doesn't work well enough on node.js scripts :(
bind --preset \cC 'cancel-commandline'
# Auto-switch nvm version on cd
# Requires a ~/.node-version file with a valid node version
# https://github.com/jorgebucaran/nvm.fish/pull/186
if type -q nvm
function __nvm_auto --on-variable PWD
nvm use --silent 2>/dev/null # Comment out the silent flag for debugging
end
__nvm_auto
end
# Pyenv setup
# Requires `brew install pyenv`
if type -q pyenv
status --is-interactive; and source (pyenv init -|psub)
end
# `ls` โ `ls -laG` abbreviation
abbr -a -g ls ls -laG
# `ls` โ `exa` abbreviation
# Requires `brew install exa`
if type -q exa
abbr --add -g ls 'exa --long --classify --all --header --git --no-user --tree --level 1'
end
# `cat` โ `bat` abbreviation
# Requires `brew install bat`
if type -q bat
abbr --add -g cat 'bat'
end
# `rm` โ `trash` abbreviation (moves files to the trash instead of deleting them)
# Requires `brew install trash`
if type -q trash
abbr --add -g rm 'trash'
end