I’ve been recently nerd-sniped by a geek friend about fish-shell (and that really says it all about what kind of person I am).

Anyways.. I’ve been a zsh and oh-my-zsh user for a long time now, way before zsh was promoted as the default shell on macOS. It’s been a fun ride, full of autocompletions, fancy themes and quick history browsing. I quite enjoyed it, especially compared to the more “dull” bash. But since I’m always up for trying out something new and living my digital life on the edge, I decided to give it a try for a while.. especially considering that at work I’m forced to use tcsh.

Autocompletion

The main “selling point” of fish is that it’s dev friendly and provides an interactive autocompletion experience. It’s hard to describe exactly how it feels while typing, that’s something you have to try to get familiar to.. here’s a quick gif to give you a hint:

In this super brief post I’ll find a very concise recap after playing around with fish for a few weeks.

One important thing to keep in mind is that fish is not POSIX compliant. This might or might not be a big deal, but it’s worth knowing that many things could just change because the writers/mantainers decided it wasn’t worth following these standards and decided to do things their own way.

If you’re interested, I definitely recommend visiting http://fishshell.com/docs/current/tutorial.html .

What follows are a few bits that I found quite core to fish’s philosophy.

Variables

Variables are definited with the set command.

$ set myvar 'Something'
$ echo $myvar
Something

Environment vars are set via set -x:

$ set -x MY_ENV_VAR 'Something'
$ env | grep MY_ENV_VAR
MY_ENV_VAR=Something

Every variable in fish is just a list: it can contain 0, 1 or more elements. List indexing starts at 1.

$ set myvar 'Something'
$ echo $myvar[1]
Something

For example, to get the first or last path in your $PATH var, you can do:

$ echo $PATH[1]
/Users/vvzen/miniconda3/bin
$ echo $PATH[-1]
/Users/vvzen/miniconda3/condabin

Since $PATH is a string variable in bash, you would do instead:

$ echo $PATH | tr ":" "\n" | head -n 1
$ echo $PATH | tr ":" "\n" | tail -n 1

Python programmers will be immediately familiar with fish’ negative indexing approach to get the last element. Accessing the first element with index 1 is a weird choice (it gave me matlab nightmares), but it is what it is.

You also have slices. This:

$ echo $PATH[1..4]

will print the first four elements in your $PATH. In bash, you could achieve something similar like this:

$ echo $PATH | tr ":" "\n" | head -n 4

Substitution

Backticks are bad, long live parenthesis (no need for the dollar sign).

$ echo I\'m (whoami) and it\'s (date +%H:%M:%S)

prints

I am vvzen and it's 14:16:52

In bash this would be:

$ echo I\'m $(whoami) and it\'s $(date +%H:%M:%S)

or

$ echo I\'m `whoami` and it\'s `date +%H:%M:%S`

Commands are not substituted within strings. You need to concatenate them:

$ echo "I am $(whoami)"

prints

I am $(whoami)

..but

$ echo "I am" (whoami)

prints

I am vvzen

Writings newlines.. in one line!

This is really neat. You can basically write multiple lines in the same command, like this:

You just write whatever you need as you would normally do, no need to manually indent since fish will adjust the indentation for you as you type the right keywords:

Wrapping it up

PROS

  • Slick ux that can considerably speed up your daily tasks
  • Good documentation
  • Great as your own personal shell

CONS

  • Adds another thing that could go wrong in the mix. Not advised for running build tasks, etc..
  • You need to re-learn a new syntax
  • Smaller user base compared to bash, zsh, etc..