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:
- put them in a version-controlled directory elsewhere and symlink to them from
- use a version-control system that doesn’t try to version-control everything in
~, like src.
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
~/.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.
- Settings that
fishlikes setting itself (colors, etc.) go in
~/.config/fish/fish_variables. (The convenience of universal variables is nice, but reading
\x1eand similar escapes is a bit of a chore for long variables.)
~/.config/fish/functions/for, well, all functions. One file per function. (fish uses functions for the sorts of things one would use an alias for in
~/.config/fish/config.fishfor everything else, including building up
$EXA_COLORSover multiple lines apiece.
? 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.
stderr-nocaret? It disables an old annoyance that I ran into.
^ isn’t anything special in
bash, but it is in
git diff HEAD^ HEAD works just fine in
bash, but you’ll want to enable
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.
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.
- Frequently, I have four different Terminal windows open to four different paths. Back when
fishdidn’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