I’ve been trying fish, however briefly, for a few years now. This time, I finally stuck with it. If you’re interested in seeing what the initial adjustment period is like, have a look at fish: the inital adjustment period.

Previously, I’d try fish only to discover that it didn’t support changing the title of Terminal.app or that fish sessions wouldn’t restore properly1. By fish 3.0.2, both of these problems were fixed and I was able to give fish a fair try.

After a bit I ended up liking it. fish bills itself as “the friendly interactive shell”. I’d describe fish as “just a little bit nicer”.

You can browse the fish site to get an idea of some of its feature set and what makes it better than other shells. This page lists some of the reasons why I like fish more than bash 3.2.57, the version that ships with macOS 10.14:

Configuration goes in ~/.config/fish/, making it easier to version-control

bash configuration tends to be sprawled at the top level of one’s home directory. In order to properly version-control bash dotfiles, one needs to either:

  1. put them in a version-controlled directory elsewhere and symlink to them from ~
  2. use a version-control system that doesn’t try to version-control everything in ~, like src.

I like src, but I can’t use it to sync changes between my desktop and laptop through a service like GitHub. ~/.config/fish/, however, is easily synced with a git push on one machine and a git pull on the other.

No profile/rc split

bash has both ~/.bashrc and ~/.bash_profile. I never really did understand when each gets loaded up. When I was first bitten by this split, I decided to write both such that they both sourced ~/.globalbashrc and that was the end of it. Later on, as I moved to Macs mostly full-time and stopped bouncing between terminals both inside and outside the X Window system, I got less defensive with my bash configuration and moved to sourcing ~/.bashrc from my ~/.bash_profile, although I couldn’t tell you why I did it this way and not the other way. At any rate, I have my $PS1-prompt twiddling and alias setup in ~/.bashrc and my $PATH prepending in ~/.bash_profile, although I couldn’t tell you why.

fish, mercifully, is much simpler, or at least it’s easier to understand where to put things.

? doesn’t glob

This is a small thing, but dagnabbit, I like it.

I use youtube-dl a fair amount. If I’m downloading a URL like https://www.youtube.com/watch?v=dQw4w9WgXcQ, I need to quote it with single quotes in bash. I don’t need to bother typing the quotes in fish if I’ve done set -U fish_features stderr-nocaret qmark-noglob first.

Why also stderr-nocaret? It disables an old annoyance that I ran into. ^ isn’t anything special in bash, but it is in fish. git diff HEAD^ HEAD works just fine in bash, but you’ll want to enable stderr-nocaret in fish to keep git and regex annoyances to a minimum.

Tab-completable makefile targets

I use simple makefiles in most of my projects. Not only do makefiles reduce the amount of typing you have to do, but they’re a useful memory aid when you return to a project after a spell and wonder “how do I make it go, again?”. Previously, in order to view makefile targets, I’d have to cat the file to see what targets were in the makefile. With fish, though, all I need to do is type make, a space, and then hit the tab-key twice.

More-accessible history

This is the feature that I end up using the most, it seems.

fish history autocompletes. Press → or C-f to complete the current suggestion. It’s a bit weird to see your old Git commit messages autocomplete when you type git commit -am, but seeing cd Projects/Go/src after just typing cd gets handy. I wouldn’t bother searching through my history and typing !234 for something like that.

If you want to keep a few commands out of your history, fish -P starts fish in private mode. I’ve used this for a screencast or two.

If these features sound neat, head on over to the fish website to find out more. If you’re wondering whether switching is a pain (it was for me, if only for a few days), have a look at my page on the initial adjustment period.

  1. Frequently, I have four different Terminal windows open to four different paths. Back when fish didn’t support session restoration, each terminal would get reset to my home directory instead of wherever its current working directory was before I quit Terminal. This was more than enough to switch back to bash↩︎