A good[ish] website
Web development blog, loads of UI and JavaScript topics
This is fish shell, the shell for the future, the shell to match your modern home terminal’s needs and requirements.
I taught myself to use fish a while ago, and now, I’m going to write a tutorial about it, and here are some of its quirks and features.
Fish is a shell, like bash, but different. Some of the selling points include, but are not limited to:
$ brew install fishSee where your fish is installed:
$ which fish
/usr/local/bin/fishNow append that to your shells file to make it available:
$ echo "/usr/local/bin/fish" >> /etc/shellsNow you can just do:
$ fishAnd you’re using fish. Go back to bash if you like:
$ exitCheck your fish version:
$ fish --version
fish, version 3.1.0Check if there’s a new version:
$ brew update
$ brew outdatedbrew update will update the homebrew package registry, and brew outdated will list out-of-date homebrew packages.
Then just upgrade fish:
$ brew upgrade fishReload your terminal window and confirm the version:
$ fish --version
fish, version 3.1.2You probably want to make it the default shell, issue the "change shell" command:
$ chsh -s /usr/local/bin/fishNow restart or refresh your terminal and it should load to Fish.
But, if you still see your old bash and you’re using iTerm2, you might have defined the shell in the iTerm2 settings (like I had), just change the setting to "Login shell":
$ chsh -s /usr/local/bin/fish again.Now iTerm should pick up fish when it restarts.
Run:
$ fish_configThat will open a web-based GUI where you can select a color theme and configure the look of the shell. When you’re done, come back to the shell and hit enter to exit the config mode.
An important directory for all fish users is ~/.config/fish. All the config lives down there.
The file ~/.config/fish/config.fish is equivalent to to .bash_profile.
From there you can export your environmental variables, for example. fish has the --export flag that you can use:
# config.fish
set --export AUTH_TOKEN blahBlahThe bash way of exporting variables seems to work, too:
export AUTH_TOKEN=blahBlahFisher makes it easy to install utilities. All you need to do is to add it to your functions directory:
$ curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fishSyntax for adding packages with fisher:
┌── GitHub path to the repo
┌─────┴────┐
fisher add jethrokuan/zThat would install z from github.com/jethrokuan/z.
Listing installed packages:
$ fisher lsWhen you install packages, fisher writes them into ~/.config/fish/fishfile. You can then subject this file to version control so you can keep your fish packages in sync between machines.
Fish is not POSIX compatible, so bash doesn’t work out of the box. But you can always do:
$ bashThat opens a bash shell, then $ exit to get back.
But if you pass it the -c option, bash will read from a string and you can stay in the current shell:
$ bash -c someBashCommandCheck man bash for more.
In fish, you can of course run scripts written in any language you imagine if the shebang is correct (#!/bin/bash). But some scripts modify the shell environment, and need to be sourced. This is what fish can’t do, but bass was designed to do just that. It’s a simple python wrapper that calls scripts in bash and passes in and out the needed environmental variables.
Install it with fisher:
$ fisher add edc/bassFor example, you can make nvm (Node Version Manager) work in fish:
function nvm
bass source (brew --prefix nvm)/nvm.sh ';' nvm $argv
endAdd that function to ~/.config/fish/functions and call nvm normally.
This bridges us up to the nvm options in fish.
We all love nvm, but nvm doesn’t work right out the box in fish. But it’s not hard to get it running.
Simply wrap nvm with bass, as shown above.
fish-nvm is an nvm written in pure fish, no shenanigans. It has worked great for me. Install it with fisher:
$ fisher add jorgebucaran/fish-nvmIf you just want something easy that works, you can stop reading now.
fast-nvm-fish is a minimal script that aims to make your shell load-up really fast even when you have multiple node version installed. It doesn’t support aliases tho.
Bash has aliases and function. Fish simplifies this by only having functions. They’re stored in ~/.config/fish/functions.
Few simple examples to showcase how the functions work:
# ~/.config/fish/functions/ls.fish
function ls
command ls --color=auto $argv
endGet the current week number:
# ~/.config/fish/functions/week.fish
function week --description "Gets the current week number"
date +%V
endReally handy function to nuke all merged git branches:
# ~/.config/fish/functions/git_delete_merged.fish
function git_delete_merged --description='Deletes merged branches'
git branch --merged | grep -v '\*' | xargs -n 1 git branch -d
endYou simply call the function by its name to execute it:
$ git_delete_mergedAbout that --description flag, it supposed to work so that you can see the description next to the function name when you tab complete. But I just can’t get it working. There used to be a bug rendering it useless, but it’s been fixed in the v3.0 of fish. Nonetheless, it doesn’t work for me.

Fish function to reload shell on Mac:
function reload --description 'Reloads shell (i.e. invoke as a login shell)'
exec $SHELL -l
endYou get the idea. Read briefly about functions from the official fish documentation, or more thoroughly in the commands documentation.
Here’s some more fish resources:
Comments would go here, but the commenting system isn’t ready yet, sorry.