Skip to content

Instantly share code, notes, and snippets.

@jvns
Last active September 4, 2024 19:53
Show Gist options
  • Save jvns/2eeb3e2ddc46e3618b6066cfeb665baf to your computer and use it in GitHub Desktop.
Save jvns/2eeb3e2ddc46e3618b6066cfeb665baf to your computer and use it in GitHub Desktop.

things julia likes about fish

(there's a little more in this blog post from 2017)

1. no configuration

In 10 years of using fish I have never found a single thing I wanted to configure. It just works the way I want. My fish config file just has:

  • environment variables
  • aliases
  • the occasional direnv hook fish | source to integrate a tool like direnv

2. autocompletion from my shell history

As I type, it’ll automatically suggest (in light grey) a command that I ran recently. I can press the right arrow key to accept the completion, or keep typing to ignore it.

Here’s what that looks like in practice: (in this example I just typed the “v” key and it guessed that I want to run the previous vim command again)

2.5 "smart" shell autocomplete

One of my favourite subtle autocomplete features is how fish handles autocompleting commands that contain paths in them. For example, if I run:

$ ls blah.txt

that command will only be autocompleted in directories that contain blah.txt -- it won't show up in a different directory. (here's a short comment about how it works)

I honestly didn't understand exactly how this worked for 10 years, it just feels like fish is magically able to suggest the right commands.

3. pasting multiline commands

If I copy and paste multiple lines, bash will run them all, like this:

[bork@grapefruit linux-playground (main)]$ echo hi
hi
[bork@grapefruit linux-playground (main)]$ touch blah
[bork@grapefruit linux-playground (main)]$ echo hi
hi

Fish will paste them all at a single prompt, so that I can press Enter if I actually want to run them. Much less scary.

bork@grapefruit ~/work/> echo hi
                         touch blah
                         echo hi

4. nice tab completion

If I run ls and press tab, it'll display all the filenames in a nice grid. I can use either Tab, Shift+Tab, or the arrow keys to navigate the grid.

Also, I can tab complete from the middle of a filename -- if the filename starts with a weird character, I can always just type something in the middle and press tab.

Here's what the tab completion looks like:

bork@grapefruit ~/work/> ls 
api/  blah.py     fly.toml   README.md
blah  Dockerfile  frontend/  test_websocket.sh

I honestly don't complete things other than filenames very much so I can't speak to that, but I've found the experience of tab completing filenames to be very good.

5. nice default prompt (including git integration)

it includes everything I want:

  • username
  • hostname
  • git integration
  • status of last command exit (if the last command failed)

The default prompt looks something like this (though there are colours):

bork@grapefruit ~/w/homepage (main) [SIGINT]>

6. great history defaults

In bash, the maximum history size is 500 by default (????). Also, by default, commands don't get added to your history until you end your session.

In fish:

  1. the default history size is 256,000 commands. I don't see any reason I'd ever need more.
  2. Commands are added to the history continuously as you run them: if you open a new tab, everything you've run is immediately available to you
  3. New commands don't get added to the history of existing terminals though, that would be weird, but they're there if you open a new terminal

(I think I'm not doing the best job explaining how the history works here)

7. Ctrl+S is disabled

Minor thing but fish disables Ctrl+S. It's a feature that I've never wanted and I'm happy to not have it.

8. fish_add_path

I have mixed feelings about this one, but in Fish you can use fish_add_path /opt/whatever/bin to add a path to your PATH, globally, permanently, across all open shell sessions. This can get a bit confusing if you forget where those PATH entries are configured but overall I think I appreciate it.

9. nice syntax highlighting

By default commands that don't exist are highlighted in red, like this:

10. easier loops

I find the loop syntax in fish a lot easier to type than the bash syntax. It looks like this:

for i in *.yaml
  echo $i
end

11. easier multiline editing

Related to loops: you can edit multiline commands much more easily (just use the arrow keys!) unlike in bash

12. Ctrl+left arrow

This might just be me, but I really appreciate that fish has the Ctrl+left arrow / Ctrl+right arrow keyboard shortcut by default for moving between words when writing a command

major downside: not everything has a fish integration

Sometimes tools don't have instructions for integrating them with fish which is annoying, but:

  • I've found this has gotten better over the last 10 years as fish has gotten more popular
  • If I need to run a POSIX shell command real quick, I can always just run bash or zsh
  • I've gotten much better over the years at translating simple commands to fish syntax when I need to

My biggest day-to-day to annoyance is probably that for whatever reason I've still not gotten used to fish's syntax for setting environment variables, I get confused about set vs set -x.

on fish as a default shell

Changing my default shell to fish is always a little annoying, I occasionally get myself into a situation where

  1. I install fish somewhere
  2. I add the new fish location to /etc/shells as an allowed shell
  3. I change my shell with chsh
  4. at some point months/years later I reinstall fish in a different location for some reason and remove the old one
  5. oh no!!! I have no valid shell! I can't open a new terminal tab anymore!

This has never been a major issue because I always have a terminal open somewhere where I can fix the problem and rescue myself, but it's a bit alarming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment