# fish: the initial adjustment period


A while ago, I switched from [`bash`][] to [`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 [`zsh`][] and [`tcsh`][].)

[`bash`]: https://en.wikipedia.org/wiki/Bash_(Unix_shell)
[`fish`]: https://fishshell.com/
[`zsh`]: https://en.wikipedia.org/wiki/Z_shell
[`tcsh`]: https://en.wikipedia.org/wiki/Tcsh

---

## 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 `!!` and `!$`. 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 `bash` settings. `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 `functions/fish_prompt.fish`:

```fish
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.

[info]: https://en.wikipedia.org/wiki/Info_(Unix)

## Settling in

The `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 `config.fish`, the `.bashrc`/`.bash_profile` equivalent. To see why, have a look at a snippet of my `fish_variables`:

```fish
# 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][pua] code points. Ick. Meanwhile, the old-fashioned way preserves the ability to logically group similar path adjustments:

[pua]: https://en.wikipedia.org/wiki/Private_Use_Areas

```fish
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:

```fish
# 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.

[exa]: https://the.exa.website 'an ls(1) replacement'

## 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 `fish` yet.

Eventually, I [found a lot of things to like about `fish`][benefits] that made me glad I switched.

[benefits]: ../fish-benefits/

