Migrating from ZSH to Fish

Fish greeting

I’ve always been using ZSH + Oh My Zsh for my shell configuration, which I have been happy with. But I recently got the urge to try out something new, and I decided to try out fish as it includes many useful features without needing extra configuration. It also has a sweet name.


Fish is not POSIX compliant, meaning you cannot use it to run your regular bash scripts. Fish-programs has to be written using the fish syntax, which seems easy enough to learn. I do little bash scripting for my regular workflow, and I plan on using fish solely as an interactive shell, so I do not think I will notice this very much


I used homebrew for a quick and easy installation:

brew install fish

I then added fish to my list of known shells, and used chsh to set fish as default. After doing these steps, I had to sign out and back in again.

sudo bash -c 'echo $(which fish) >> /etc/shells'
chsh -s $(which fish)

I also had to use the fish_add_path command for fish to recognize programs installed by homebrew:

fish_add_path /opt/homebrew/bin

Configuring fish

As I mentioned earlier, fish is very useable without any configuration, which I like. I, therefor, have decided to keep my config as clean as possible, without relying on any plugins.

The first thing I did was to set the fuck alias, and disable the autosuggestion by default, as I found it distracting. I did this in .config/fish/config.fish.

# ~/.config/fish/config.fish

thefuck --alias | source
set -g fish_autosuggestion_enabled 0

I then found a pretty greeting-function and modified it a bit to only print the greeting for large windows that open in ~, as I do not want it cluttering the screen while I’m working on something.

# ~/.config/fish/functions/fish_greeting.fish

function fish_greeting
  if test $LINES -gt 25; and [ (pwd) = $HOME ]
    echo '                 '(set_color F00)'___
  ___======____='(set_color FF7F00)'-'(set_color FF0)'-'(set_color FF7F00)'-='(set_color F00)')
/T            \_'(set_color FF0)'--='(set_color FF7F00)'=='(set_color F00)')    '(set_color red)(whoami)'@'(hostname)'
[ \ '(set_color FF7F00)'('(set_color FF0)'0'(set_color FF7F00)')   '(set_color F00)'\~    \_'(set_color FF0)'-='(set_color FF7F00)'='(set_color F00)')'(set_color yellow)'    Uptime: '(set_color white)(uptime | sed 's/.*up \([^,]*\), .*/\1/')(set_color red)'
 \      / )J'(set_color FF7F00)'~~    \\'(set_color FF0)'-='(set_color F00)')    IP Address: '(set_color white)(ipconfig getifaddr en0)(set_color red)'
  \\\\___/  )JJ'(set_color FF7F00)'~'(set_color FF0)'~~   '(set_color F00)'\)     '(set_color yellow)'Version: '(set_color white)(echo $FISH_VERSION)(set_color red)'
   \_____/JJJ'(set_color FF7F00)'~~'(set_color FF0)'~~    '(set_color F00)'\\
   '(set_color FF7F00)'/ '(set_color FF0)'\  '(set_color FF0)', \\'(set_color F00)'J'(set_color FF7F00)'~~~'(set_color FF0)'~~     '(set_color FF7F00)'\\
  (-'(set_color FF0)'\)'(set_color F00)'\='(set_color FF7F00)'|'(set_color FF0)'\\\\\\'(set_color FF7F00)'~~'(set_color FF0)'~~       '(set_color FF7F00)'L_'(set_color FF0)'_
  '(set_color FF7F00)'('(set_color F00)'\\'(set_color FF7F00)'\\)  ('(set_color FF0)'\\'(set_color FF7F00)'\\\)'(set_color F00)'_           '(set_color FF0)'\=='(set_color FF7F00)'__
   '(set_color F00)'\V    '(set_color FF7F00)'\\\\'(set_color F00)'\) =='(set_color FF7F00)'=_____   '(set_color FF0)'\\\\\\\\'(set_color FF7F00)'\\\\
          '(set_color F00)'\V)     \_) '(set_color FF7F00)'\\\\'(set_color FF0)'\\\\JJ\\'(set_color FF7F00)'J\)
                      '(set_color F00)'/'(set_color FF7F00)'J'(set_color FF0)'\\'(set_color FF7F00)'J'(set_color F00)'T\\'(set_color FF7F00)'JJJ'(set_color F00)'J)
                      (J'(set_color FF7F00)'JJ'(set_color F00)'| \UUU)
                       (UU)'(set_color normal)

I also customized the default prompt. I took inspiration from the prompt I had been using from Oh My Zsh (avit), and created a similar looking one for fish:

# ~/.config/fish/functions/fish_prompt.fish

function _git_branch_name
  echo (command git symbolic-ref HEAD 2> /dev/null | sed -e 's|^refs/heads/||')

function _git_is_dirty
  echo (command git status -s --ignore-submodules=dirty 2> /dev/null)

function fish_prompt
  set -l last_status $status

  set -l cyan (set_color cyan)
  set -l yellow (set_color yellow)
  set -l red (set_color red)
  set -l blue (set_color blue)
  set -l green (set_color green)
  set -l normal (set_color normal)

  set -l cwd $blue(pwd | sed "s:^$HOME:~:")

  # Add a newline before new prompts
  echo -e ''

  if set -q VIRTUAL_ENV
      echo -n -s (set_color -b cyan black) '[' (basename "$VIRTUAL_ENV") ']' $normal ' '

  echo -n -s $cwd $normal

  if [ (_git_branch_name) ]
    set -l git_branch (_git_branch_name)

    if [ (_git_is_dirty) ]
      set git_info $green $git_branch $red " ✗" $normal
      set git_info $green $git_branch ' ✔'
    echo -n -s '  ' $git_info $normal

  set -l prompt_color $red
  if test $last_status = 0
    set prompt_color $normal

  echo -e ''
  echo -n -s "$normal▶ "

Neovim configuration

I installed fish grammar for treesitter to get syntax highlighting in Neovim. I also had to install ripgrep from homebrew to get telescope live grep working.

:TSinstall fish
brew install ripgrep


I’ve been using fish for the past couple of days now, and I have to say that I like it alot. After configuring everything, I’ve noticed how fast the prompt appears compared to Oh My Zsh. I’ve also been really impressed with fish_config, which let’s you do some configuration from a web interface. This was really useful when deciding on colors for my prompt. I’ve also been liking the prevd and nextd commands which are mapped to alt + left/right arrow. I also really like that ctrl+c is shown after terminating stuff.

If you want to copy my setup, feel free to check out my dotfiles!

Reply via email