fish (Shell) for a Week

I’ve been meaning to try out [fish]( for ages, and I was finally inspired to dive in after reading [Julia Evans’ recent take]( on it. In this post, I’ll describe some highlights from my first week.

##Installation and Setup
fish is easy to install: It’s available in both [Homebrew]( and [APT]( After you’ve tested it and are ready to make it your system default, you can select it with `chsh -s`, but be warned that on OS X, you’ll first need to add an entry to `/etc/shells`.

One of the first things you’ll probably want to do when switching shells is to put a few things on your executable path. To do this, open up `~/.config/fish/` and add a line like `set PATH /usr/local/Cellar/mtr/0.87/sbin $PATH` .

It’s also likely that you use a few tools that integrate with your shell and required manual setup when you first installed them. For me, the first two that I missed were [autojump]( and a rudely-named [command corrector]( For tools installed via Homebrew (as these are), you can usually get a refresher on the installation instructions with e.g. `brew info autojump`.

Version managers are great, but they can easily destroy your shell startup time. I’ve been frustrated with that situation in the past, so with this in mind, I decided to try [fast-nvm-fish]( It’s less feature-rich than a typical nvm installation (notably, aliases don’t work properly), but I’m able to easily switch between installed node versions with e.g. `nvm use 6.10.3`, which is all I really need.

I haven’t needed any other version managers ([rbenv](, [pyenv](, etc.) yet, so I can’t speak to their compatibility. fish is notably [not POSIX-compliant](, so be prepared for a little extra work to configure lesser-used tools.

fish has a bunch of cool features, like a wide color palette and a convenient web-based configuration interface, but these are my favorites:

###Searchable History
fish’s history search is much more intuitive than Bash’s. Type a substring of the thing you want, and browse matches with up/down (or ctrl+p / ctrl+n):

###Really Smart Tab Completion
My other favorite feature is fish’s tab completion, which uses information from a variety of sources.

The _file seeking_ completion makes my life easier. It seems like a minor improvement over Bash, but fish’s ability to match substrings _within_ filenames flattens out a frequent speedbump. For example, the other day I entered `/Applications/Az` *(TAB)*, and fish expanded it into `/Applications/Microsoft\ Azure\ Storage\`. This is exactly what I wanted, though I didn’t know that the directory started with an M.

fish also has handy completion of command line arguments. Here I search the _description_ of a git command line argument, and then search for a remote branch:

Note also that fish shows you completions before you even hit tab; press the right arrow (or ctrl+f) to accept the current suggestion.


Though I occasionally write commands with unreasonable numbers of pipes (e.g. `git status |grep \.js |awk ‘{print $2}’ |xargs git checkout -f`), I’m not a very heavy user of shell scripting. That said, there are some big differences between how fish and Bash do common scripty things. They are [documented well](, but here are the first few I encountered:

# Short circuit:
foo && bar      # bash
foo; and bar    # fish

# Redirect stderr: 
./foo 2>outfile # bash
./foo ^outfile  # fish

# Command substitution: 
file `which ls` # bash
file (which ls) # fish

##I’m Hooked!
I’ve used Bash for years, for the same reason that I suspect everyone else does: It was the default on the Unix systems on which I learned. fish is a great candidate shell to overcome Bash’s inertia in your life because 1) it’s easy to install, and 2) it yields benefits before you climb very high on its learning curve.

I expect to stick with this shell for the foreseeable future. What are you waiting for? Give it a try!

  • Martin says:

    Hi John,

    Landed here while researching on how people usually run fish+nvm on macOS :)

    Fish is awesome, indeed, I’ve been using it for a long time. Did you know about Elvish? /

    While I believe it has a great potential I’ll stick to Fish for now because bobthefish <3

  • I like Fish too but stopped using it because of fish and Bash differences you mentioned

  • Serge Lussier says:

    I hate so much shell scriptings. Because of its limitations and weirdoes. Like Bash: if:fi case:esac; and …no floating points! The only useful (posix?)syntax are “command && success-code || fail-code” – But Fish 3.0 introduces it :)

    And I don’t understand why the world is complaining against Fish that is supposedly not posix… But try run a foreign shell script in a given shell without subshell’ing in that foreign shell… Duh!

    In Fish :

    No weird keywords. Just like any “NORMAL” programming languages.

    But all shells no exceptions : Inputs from stdin: Keyboard is very, very limited. No real Control-Keys support. ( arrow keys, function keys, etc. CTRL-[xxx]; shift-[xxx]; alt-[xxx]-super-[xxx]) – System programmers are too lazy to handle inputs from physical device versus terminal TTY controls commands.

    In 2019, there is two kind of interractive comm : Keyboards and Mices and now EVERY CLIENTS run on real computers with at least a phsysical keyboard attached. No more “Virtual TTY”. Fish does not escape it. So Fish is as interactive as Bash and co. => NOT SO!

    Thanks :) Hehehehehe!

  • Comments are closed.