Try Out Fish For Your Command Line Shell
Henry Bley-Vroman, Former Senior UI Developer
Article Categories:
Posted on
Not into heavily configuring your terminal? Right out of the box, the fish shell will transform your CLI experience.
Updates
Abbreviations are now available in zsh. Check out my plugin zsh-abbr!
In the article Configure Zsh Options & Plugins for Productivity in macOS's Default Shell I walked through customizing zsh's interactive shell to add what I consider key features. (An "interactive shell" is the shell as experienced in a terminal, as opposed to when writing shell scripts.) In the end we had nice history management, a shorthand for cd
, the ability to jump to a directory we were in several cd
s back, command completion with an interactive menu, inline suggestions, completions for various programs, an intuitive way to filter history, syntax highlighting in the terminal, and an informative prompt. In short, the result was interactive shell that felt smart and helped us find and do things more quickly without any need to learn additional tools.
But getting zsh there took significant configuration. There are other approaches — Oh My Zsh, for example, is an enormous collection of zsh configurations you install in one go. Oh My Zsh did a lot to popularize zsh as a shell for people who wanted a great interactive shell experience and snazzy prompt. But it includes more customization and extension than most people need or will even discover, and as each of those confers a (usually small) performance hit some long-term users end up switching to a more paired-down configuration — that's what the previous post is.
There's a much easier way: switching to fish. fish is a shell that puts the command line experience first. Out of the box it comes with almost everything in my recommended zsh setup circa 2019, and a lot more. In fact, many of the plugins in that zsh setup are inspired by built-in fish features, and they don't always live up to the original.
zsh is still a wonderful shell. Its comprehensive builtins and elegant syntax make all kinds of cool programming tight. But if you spend much time running commands in a terminal, try fish there.
Installing fish
fish is available for macOS, Linux, BSD, Windows, and as source. It's probably distributed in whatever way you expect packages for your system to be distributed in. There are links on the fish homepage (note: the homepage might be too cute for its own good. If you're looking for a starting guide, jump straight to the Tutorial).
On macOS, you can install fish with Homebrew:
brew install fish
and then make it available to the system by adding /usr/local/bin/fish
to your /etc/shells
.
Installing fish doesn't commit you to using it. You can switch an individual session to fish by running fish
.
Any other open sessions (i.e. other open terminal windows) and any other sessions you start won't be affected. If you want to get out of your fish session and switch it to bash or zsh or anything else just run bash
or zsh
etc.
If you're coming from bash, fish will automatically import your history (and here's the procedure for merging bash history into an existing fish history). If you're coming from zsh and want to migrate your history over, there's rsalmei/zsh-history-to-fish (and here's the procedure for merging zsh history into an existing fish history).
If you decide to make fish your default shell, run chsh -s /usr/local/bin/fish
Comparing fish and zsh interactive shells
Here's a rundown of the features in my recommended zsh setup circa 2019. Tl;dr: fish does it out of the box. All zsh configuration instructions are given in Configure zsh Options & Plugins for Productivity in macOS's Default Shell.
Feature | Fish | zsh |
---|---|---|
Save history to a file | Yes! | If configured |
Trim history | Yes! Limited to 256K unique commands (which is a ton). Least recently used are trimmed first | If configured. Trims from end. Can configure to trim duplicates before uniques. |
Timestamp history records | Yes! | If configured |
Dedupe the history | Yes! | If configured |
Keep space-prefixed commands out of the history | Yes! | If configured |
Share history across open terminals | If configured. Configure manually or with a plugin manager | If configured |
"auto-cd" - mydir is shorthand for cd mydir | Yes! | If configured |
Navigate directory stack | Yes! With browser-like back/forward or by index | If configured, by index. No browser-like "forward" - previous directory is always top-of-stack |
Command completions (with TAB) | Yes! First TAB inserts the top-ranked completion. Second opens an interactive menu of all possibilities. Menu clears if you change the input or esc | If configured. Depending on configuration, TAB either cycles through inserting the possibilities or opens an interactive menu. If you change the input, menu persists until you TAB again but is unusable |
Case insentivity | "Case correcting." fish has a multilevel ranking of how good a match something is. Key takeaway is exact matches are prefered over wrong-case matches. Decides whether to show multiple suggestions based on the strength of the available matches. | If configured. Highly customizable. |
Color coded completion menus | Yes! Plus additional context such as object type and size | If configured |
Suggestions as you type | Yes! Based on history and completions, and will not suggest commands that are in history but which are no longer available | With a plugin. Plugin does not filter out commands that are no longer available |
Program command completions (e.g. git co<tab></tab> ) | Yes! For common programs. Plus simple syntax for writing your own completions, and simple support for developers to distribute completions along with software | Yes! For common programs. Add plugins to add completions not shipped with zsh. Writing completions requires shell scripting knowledge |
History substring search | Yes! For example type commit and then use the UP and DOWN keys to navigate history records which contain "commit" | With a plugin. Binding to arrow key navigation requires additional configuration |
Syntax highlighting | Yes! | With a plugin |
Selection of prompts | Yes! Ships with over a dozen. Can install more, or write your own | Can install or write your own |
Other great fish features
fish has a bunch of things going for it that other common shells don't. Here are a few that jump out:
- Startup and each new prompt are fast! The fish maintainers have invested time in making the interactive shell experience load quickly.
- History search, with globbing! Run
history search "my command"
to search for instances of "my command" in your history. Or runhistory search "my*gl?b"
to search for instances of "my*gl?b". - 🆕 Abbreviations are now available in zsh. Check out my plugin zsh-abbr! Abbreviations! They're similar to standard aliases, but they expand inline. If you have the abbreviation "gc" for "git commit",
gco<space></space>
will immediately be replaced withgit commit
andgco<enter></enter>
will be replaced withgit commit
and the command will be run. This means you can save keystrokes without forgetting the full command, and your history will be more meaningful. Adding abbreviations is simple: to create that "gc"/"git commit" abbreviation, runabbr gc git commit
. More options are available — runabbr --help
to see them. - Beginner-friendly documentation.
- Discussion and contribution happen on GitHub, making the bar for entry low (zsh is mailing list-based; bash has a Savane tracker; ksh is on GitHub but currently the few maintainers have their hands full with modernizing the codebase)
- Web UI for essential configurations. fish really doesn't want you to have to be a shell scripter to fine tune your interactive shell. Run
fish_config
to open a browser window where you can- visualize and choose between various color schemes (I control this in my terminal app though, not with fish),
- visualize and choose between prompts,
- see all the functions built into the shell,
- see all global variables and their values,
- see your history and delete any records,
- see all configured key bindings (ie keyboard shortcuts),
- and see your abbreviations and delete any of them.
I still enjoy digging through the zsh docs and spending weekends fiddling with the configuration. If that isn't you, check out fish. It's like like switching from dollar store foam headphones to nice noise-cancelling ones, except free: you do nothing, and suddenly things you didn't know could be better are.