A while ago, I switched from
fish. This time, I stuck with it. After reading this, you should have a better idea of the hassles involved with switching to a new shell.
(I’m going to assume that you know what a shell is. While I don’t expect you to have used anything other than
bash, I assume you’ve heard of other shells like
Even an old version of
bash is good enough
Let’s get this out of the way:
bash ain’t half bad.
command.com, used for both DOS and Windows, didn’t even do command tab completion.
cmd.exe, used in Windows NT up through Windows 10, only started doing command completion by manually changing a setting.
bash does this out of the box. Furthermore, even an old version of
bash, like the 3.2 that ships with macOS 10.14 Mojave, does all this. (Every so often I check
bash’s NEWS file; none of the additions seem memorable enough to justify switching to a new version.)
bash also has nifty-keen substitution parameters like
!$. They’re handy.
Initially everything is just a little bit wrong
As you might expect, a fresh
fish shell is way different from my moderately-customized
fish color settings aren’t too important, but I’m used to my style of prompt and I didn’t want much, if anything, to change about it. The biggest annoyance?
fish automatically shortens paths in prompts. That is,
~/Pictures/Funny/Autocorrect Failures would get shortened to
~/P/F/Autocorrect Failures and I’d have to type
pwd to reorient myself in the file system hierarchy. Piecing together different prompts and their writing styles, I eventually settled on this
function fish_prompt --description 'Write out the prompt' set -l last_status $status # `set -U ARROW_ONLY yes` and `set -eU ARROW_ONLY` to toggle # good for presentations if test -n "$ARROW_ONLY" echo '> ' return end if test $last_status -ne 0 printf "%s(%d)%s " (set_color red --bold) $last_status (set_color normal) end set -l color_cwd set -l suffix switch "$USER" case root toor if set -q fish_color_cwd_root set color_cwd $fish_color_cwd_root else set color_cwd $fish_color_cwd end set suffix '#' case '*' set color_cwd $fish_color_cwd set suffix '>' if set -q fish_private_mode set suffix '»' end end # set $fish_prompt_pwd_dir_length to 0 to disable shortening in prompt_pwd echo -n -s \ (set_color --bold $fish_color_user) \ "$USER" @ (prompt_hostname) \ ' ' \ (set_color --bold $color_cwd) \ (prompt_pwd) \ (set_color normal) \ " $suffix " end
It’s a bit fancier than my old
$PS1, but it’s still reasonably clear to read for a novice like me. While the documentation for
$fish_prompt_pwd_dir_length wasn’t easy to find, everything else was. This was a refreshing change compared to what I remember of
bash documentation. With
bash’s web-based info pages, I never seemed to be able to find how to do anything I wanted and had to rely on other sites to explain
bash’s feature set to me.
fish documentation talks about universal variables. At first blush, variables that are shared between all instances of a shell sounded like a useful idea. Every so often I’ve wanted to change something about
bash and had to paste-and-run
source ~/.bashrc in all my running
bash instances. This is an annoyance, if an infrequent one. Unfortunately, I found it’s much more useful to be able to put my variable settings — and especially additions — in
.bash_profile equivalent. To see why, have a look at a snippet of my
# This file contains fish universal variable definitions. # VERSION: 3.0 SETUVAR __fish_init_2_39_8:\x1d SETUVAR __fish_init_2_3_0:\x1d SETUVAR __fish_init_3_x:\x1d SETUVAR fish_color_autosuggestion:BD93F9 SETUVAR fish_color_cancel:\x2dr SETUVAR fish_color_command:normal # … SETUVAR fish_pager_color_prefix:white\x1e\x2d\x2dbold\x1e\x2d\x2dunderline SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan SETUVAR fish_prompt_pwd_dir_length:0
Now imagine trying to edit your
$PATH if it were separated by not just colons, but backslash-escaped UTF-8 byte sequences of Private Use Area code points. Ick. Meanwhile, the old-fashioned way preserves the ability to logically group similar path adjustments:
set -x PATH $HOME/Library/Python/2.7/bin $PATH set -x PATH /Library/Frameworks/Python.framework/Versions/2.7/bin $PATH set -x PATH /Library/Frameworks/Python.framework/Versions/3.5/bin $PATH set -x GOPATH $HOME/Projects/Go set -x PATH $HOME/Projects/Go/bin $PATH set -x PATH $HOME/bin $PATH
This is doubly important for anything that needs to be documented on a per-chunk basis:
# for xterm-256color: # # - 38;5 — next number sets text color # - 48;5 — next number sets background color # # (colors at, say, <https://i.stack.imgur.com/UQVe5.png>) set -x EXA_COLORS set -a EXA_COLORS "di=38;5;69" # directories set -a EXA_COLORS "da=38;5;195" # times set EXA_COLORS (string join ":" $EXA_COLORS)
While it’d be neat to have exa colors propagate instantly, editing its
fish_variables entry would be as fun as editing a 120-column, one-line regular expression.
Yes, this is a lot of busywork
If all this sounds like I’m doing lots of work to merely get my
fish setup to be as good as my
bash setup, you’re right. What’s more, I hadn’t really seen any of the benefits of
Eventually, I found a lot of things to like about
fish that made me glad I switched.