Set up fish, the user-friendly interactive shell hero

Set up fish, the user-friendly interactive shell

Fish (Friendly Interactive SHell) is a Unix shell designed to be user-friendly and interactive. It features syntax highlighting, autosuggestions, and a built-in help system, among other features. Fish aims to be more intuitive and easier to use than traditional Unix shells like Bash, while still providing powerful scripting capabilities. Modern macOS computers ship with zsh as the default shell, you can check out Why I Switched from zsh to fish but the main reasons are the speed, simplicity, autosuggestions and vim mode that the fish shell offers.

Installing fish

Fish does not come pre-installed on macOS, you have to install it with Homebrew by running the following command in the terminal.

Terminal window
brew install fish

If you’re not familiar with Homebrew, check out Managing macOS packages with Homebrew.

Making fish your default shell

Now that the fish shell is installed, you have to manually change the default shell by completing the following steps.

First, you will need to get the path to the fish shell executable. If you’re unfamiliar with how executables in the terminal work, I recommend checking out What is the terminal?. Run the following which command.

Terminal window
which fish

The command will output something similar to /opt/homebrew/bin/fish. Copy the value from your terminal and add it to the /etc/shells file. You’ll want to edit the file using the sudo command, since this is an system-level file that lists valid login shells for user accounts. Here is how to update it using vi.

Terminal window
sudo vi /etc/shells

Enter your user password to open the file then add the fish shell’s path as an new line in the file and save it.

/etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.
/opt/homebrew/bin/fish # use output from `which fish`
/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

If you’re unfamiliar with vi, I recommend running vimtutor in your terminal which will guide you through the basics of how to edit text from inside the terminal.

Now that you’ve added fish as a valid login shell for macOS, you can run the chsh (change shell) command to change the default login shell.

Copy the command below and run all three commands at once to quickly change your default shell to fish.

Terminal window
cd ~
basename $(pwd) | pbcopy
chsh -s /opt/homebrew/bin/fish $(pbpaste)

You may be prompted, again, to enter your user password and when the command is completed your login shell is now switched to fish. In order for your changes to take effect, you’ll need to log out and log back in to your user account. I recommend you restart your computer for good measure. When you log back in fish will be your default shell, congrats!

Configuring fish

Fish configuration is written in its own scripting language. The entry point for configuring the fish shell is the config.fish file which can be created with the following command.

Terminal window
mkdir -p ~/.config/fish && touch ~/.config/fish/config.fish

This command first creates the ~/.config/fish directory with the -p option, which creates any parent directories that do not exist. Then it creates the config.fish file inside the ~/.config/fish directory using the touch command. Note: all of fish’s configuration files are stored in ~/.config/fish more of which will explore later.

Configure homebrew

I highly recommend you Manage macOS packages with Homebrew. Add the following eval code to your config file to configure homebrew with the fish shell.

~/.config/fish/config.fish
eval (/opt/homebrew/bin/brew shellenv)

Note: Evaluating a command in the shell is typically done with $(cmd) but fish uses (/cmd) instead, dropping in the $. Some developers I’ve talked have chosen not to use fish because of the subtle syntax differences from more traditional shells, but I think it’s worth it.

Add directories to PATH

In fish, the fish_add_path function is used to add directories to the PATH environment variable. Adding directories to your system’s PATH environment variable allows you to run programs located in those directories from anywhere on your system without specifying the full path. By doing so, you extend the list of directories that the shell searches for executables, making it more convenient to run programs and execute commands.

To add support for Homebrew executables to the fish shell, add the following lines to your ~/.config.fish file.

~/.config/fish/config.fish
fish_add_path ~/.config/bin

I recommend creating a ~/.config/bin directory to store any custom scripts you make come up to improve your workflow or automate tasks.

Setting environment variables

In the Fish shell, the set command is used to create and modify shell variables. Shell variables are used to store values that can be referenced and reused throughout a shell session or script. Here are some common variables that are helpful.

~/.config/fish/config.fish
set -U fish_greeting # disable fish greeting
set -U fish_key_bindings fish_vi_key_bindings

The -U flag is used with the set command to create or modify a universal variable. Universal variables are similar to regular variables, but they have a global scope and can be accessed from any shell session or script.

The fish_greeting variable is used to customize the greeting message that is displayed when a new shell session is started. By default, the greeting message includes the Fish version number and a welcome message. Since I am constantly spinning up new shells in my development workflow, I prefer to disable the fish greeting by setting it with not value.

The fish_vi_key_bindings variable allows you to hit escape while writing a command in fish to switch to a vi-mode to easily manipulate your command before running it. Just like vi, you can hit i to get back to insert mode. There are many other variables you can set to customize your shell, check out the fish documentation for more information. The next most common variable to change is the default editor for your shell. This is set with the EDITOR variable.

~/.config/fish/config.fish
set -Ux EDITOR nvim

Note the -x flag is used with the set command to export a variable as an environment variable. When a variable is exported, it becomes available to child processes and can be accessed by programs and utilities that use environment variables. This is helpful as you extend your development environment with other tools that can generate sub processes

Abbreviations

One of my favorite features of fish is the ability to create abbreviations. This works similar to a shell aliasm but the main difference is the abbreviation will expand when ran.

You can create abbreviations with the abbr command in your config.fish file. Let’s add a few helpful ones for homebrew.

~/.config/fish/config.fish
abbr bi "brew install"
abbr bic "brew install --cask"
abbr bin "brew info"
abbr binc "brew info --cask"
abbr bs "brew search"

You’ll have to source your config.fish file for the change to be reflected in your shell.

Terminal window
source ~/.config/fish/config.fish

Now, you type bs<space> and you’ll see the prompt quickly expand to brew search to allow you to create commands quickly using a simple mnemonic-style abbreviations. Abbreviations speed up my dev workflow significantly and are one of my favorite features of the fish shell.

Plugins

There is a large community of plugins for the fish shell. I recommend using fisher to manage them.

Terminal window
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher

A great starter plugin for fish is sponge, which cleans your fish history from typos automatically. It can be installed with the fisher command.

Terminal window
fisher install meaningful-ooo/sponge

You’ll notice two things.

  1. A ~/.config/fish/fish_plugins file was created and added sponge as a plugin. This is how fisher manages plugins.
  2. A ~/.config/fish/functions directory was created and multiple _sponge_*.fish files were added to it. This is the plugin code which fish will automatically read to extend the shell. This folder will contain more files as you add more plugins, you can even create your own!

Summary

The fish shell is a simple, fast, and intuitive shell alternative for macOS. In this post we installed fish, set it as your default user shell, configured homebrew, added a directory to your path, customized some of fish’s options, create abbreviations, and installed your first plugin.

Sign-Up for New Posts

Stay in the loop and get the latest blog posts about dotfiles sent to your inbox.

man sitting at desk in front of a landscape of rivers leading to a mountain range

Dev Workflow Intro

Your guide to creating a powerful and intuitive development workflow in the terminal.

The terminal is a powerful tool for developers, but it can be overwhelming to know where to start. This guide will help you create a powerful development environment in the terminal. Here are some of the things you'll learn.

  • Install packages and keep them up-to-date
  • Design a minimalist, distraction-free, user-interface
  • Use familiar keyboard shortcuts
  • Manage multiple projects with ease
  • Integrate with Git and GitHub
Get Started