sudo apt-add-repository ppa:fish-shell/release-3
I’ve finally made the switch from ZSH to the fish shell. Unlike ZSH, I don’t need to install and manage a whole host of plugins. Everything I want comes packaged right in as part of the shell itself.
In this post, I describe how to switch to the fish shell and some of the interesting features it offers.
Once installed, switching is just a matter of updating the login shell.[1]
Register /usr/bin/fish
as a login shell by adding its path to /etc/shells
.
Debian provides a convenient add-shell
command to accomplish this.
sudo add-shell /usr/bin/fish
Set the current user’s login shell to fish with chsh
.
chsh -s /usr/bin/fish
Password:
Now, open up a fresh terminal session to start using fish.
You should see a fresh, vanilla shell prompt like the following.
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
jordan@jwillkers ~>
Adjusting basic configuration options is quick ang easy with fish.
Configuring the fish shell is as easy as selecting options the provided by the web interface.
fish_config
Style the prompt.
If you like that oh-my-zsh feel as I do, you might want to use robbyrussell’s theme for your shell prompt. If you like doing things the old fashion way - or want to set the prompt remotely, here’s a quick rundown.
Make sure the ~/.config/fish/functions
directory exists.
mkdir -p ~/.config/fish/functions
Then copy over the desired prompt configuration, robbyrussell.fish
in this case, from /usr/share/fish/tools/web_config/sample_prompts/
.
cp /usr/share/fish/tools/web_config/sample_prompts/robbyrussell.fish ~/.config/fish/functions/fish_prompt.fish
Adjust the color theme.
The color theme can be important when your terminal’s color theme obscures autosuggestions.
Solarized is my color scheme of choice.
The fish_config
web tool outputs the commands that set the various variables for a color theme when one is selected.
This is easy to translate to a command-line which can be quite helpful when configuring remotely.
As an example, the following command sets the color scheme to solarized dark.
set -U fish_color_normal normal; \
set -U fish_color_command 93a1a1; \
set -U fish_color_quote 657b83; \
set -U fish_color_redirection 6c71c4; \
set -U fish_color_error dc322f; \
set -U fish_color_end 268bd2; \
set -U fish_color_selection white --bold --background=brblack; \
set -U fish_color_search_match bryellow --background=black; \
set -U fish_color_history_current --bold; \
set -U fish_color_operator 00a6b2; \
set -U fish_color_param 839496; \
set -U fish_color_cwd green; \
set -U fish_color_cwd_root red; \
set -U fish_color_valid_path --underline; \
set -U fish_color_autosuggestion 586e75; \
set -U fish_color_user brgreen; \
set -U fish_color_escape 00a6b2; \
set -U fish_color_cancel -r; \
set -U fish_pager_color_completion B3A06D; \
set -U fish_pager_color_description B3A06D; \
set -U fish_pager_color_prefix cyan --underline; \
set -U fish_pager_color_progress brwhite --background=cyan; \
set -U fish_color_host normal; \
set -U fish_color_match --background=brblue; \
set -U fish_color_comment 586e75
Customize the greeting message with the variable fish_greeting
.[2]
set -U fish_greeting ""
Enable backwards-incompatible features.[3]
set -U fish_features stderr-nocaret qmark-noglob
Enable Vi mode.
For user’s who prefer Vi and Vim, there is a nifty method of enabling Vim keyboard shortcuts in addition to the default Emacs shortcuts. Creating the file below will enable this and default to insert mode.
function fish_user_key_bindings
fish_default_key_bindings -M insert
fish_vi_key_bindings insert
end
Override the ~/.config/fish/functions/fish_mode_prompt.fish
|
Now, if you’re thinking about .fishrc
, forget about it.[4]
The equivalent of ~/.bashrc
and ~/.zshrc
is ~/.config/fish/config.fish
but a lot of configuration is better achieved - and organized - through universal variables and autoloading functions.
Update the PATH
environment variable in fish to suit your needs.[5]
Version 3.2.0 of fish introduced the command fish_add_path
which makes permanently adding a path to PATH
super easy.
Just use use the command followed by the path to add, and that’s it!
No fiddling with configuration files necessary.
It takes care of duplicates for you, too.
Some Linux distributions don’t include /usr/local/bin
in PATH
by default.
Adding /usr/local/bin
to the end of the list in PATH
is as simple as this.
fish_add_path /usr/local/bin
The -p
flag prepends the given path to PATH
.
To place /usr/local/bin
at the beginning of PATH
, use this command.
fish_add_path -p /usr/local/bin
When messing with PATH
prior to version 3.2.0, use fish’s dedicated internal variable fish_user_paths
.
This variable is special and populates PATH
.
With the set
command, prepend /usr/local/bin
to PATH
as follows.
set -pU fish_user_paths /usr/local/bin
The -p
option prepends a value to the given variable.
The -U
option signifies a universal variable, which persists the variable in the future and across any currently running fish sessions.
This reduces the overhead of having to mess about with shell startup files.
These variables can be managed in the file ~/.config/fish/fish_variables
.
A lot of fish functionality has been covered already, but "there’s always more to learn" as they say. A few additional fish topics are covered here.
Export shell variables with the -x
flag.
This makes the variables accessible to other programs.
PATH
is automatically exported from the contents of the un-exported fish_user_paths
variable, making this an exception.
For everything else, export the variable by calling set
with the -x
flag.
To add a value to the beginning of the LD_LIBRARY_PATH
environment variable and export it, use set
as follows.
set -px LD_LIBRARY_PATH /usr/local/lib
Understand how fish handles PATH variables.
The fish shell stores lists internally as arrays of strings.
This is fundamentally different from how shells typically represent many fundamental variables which contain lists of paths, such as PATH
and LD_LIBRARY_PATH
.
Classic shells store these "lists" as a single string of colon-separated paths.
Many applications and programs expect the incumbent formatting, so fish treats these as special variables called PATH variables.
When printing or joining PATH variables, colons are used to delimit values when the variables are quoted.
Otherwise, spaces separate each path in the list.
Any variable ending in PATH
is automatically treated as a PATH variable.
So, when using set
to deal a PATH variable, you can still treat it as you would any other list in fish.[6]
As an example, the following command adds /usr/local/lib
to the beginning of the classic LD_LIBRARY_PATH
variable and appends ~/lib
to the end.
set -x LD_LIBRARY_PATH /usr/local/lib $LD_LIBRARY_PATH ~/lib
When quoting the variable, it must be modified like so to achieve the same result.
set -x LD_LIBRARY_PATH /usr/local/lib:"$LD_LIBRARY_PATH":~/lib
Take advantage of autosuggestions.
Just start typing a command and fish will provide suggestions on your prompt. As autosuggestion appear from your history, choose the suggested line with →. To select only the next word of the suggestion, use Alt+→.
Use fish’s searchable history instead of Bash’s reverse history search.
This one has required a bit of learning curve since I’m so used to finding previous commands by searching with Ctrl+R. With fish, this is even simpler. Start typing the letters, word, or phrase you want to match. Then, just press Alt+↑ to scroll backwards through history for matches.
Another nifty feature is the recursive wildcard which automatically descends into subdirectories for matching a particular pattern.
The following example recursively searches and lists all files ending in .fish
in ~/.config
.
ls ~/.config/**.fish
/home/jordan/.config/fish/functions/fish_prompt.fish
Common issues involve various environment variables and initialization functionality which assumes the default login shell is Bash.
Some people place fish
in their ~/.bashrc
file to start fish from within Bash so that all environment variables are correctly configured.
I prefer to use fish
as my login shell and file bugs as necessary for projects to properly support it, but this is definitely a bit a of a pain but thus is progress, eh?
There’s a lot to learn about the fish shell. It provides an extremely convenient feature set and is attempting to solve issues inherited from shells of generations past. I love it, and its a great improvement to my workflow.