Fish (the “friendly interactive shell”) has the explicit goal of being more user-friendly than other shells. It features a modern command-line interface with syntax highlighting, tab completion, and auto-suggestions out of the box (all with no configuration required). Unlike many of its competitors, it doesn’t care about being POSIX-compliant but attempts to blaze its own path.
Since our last look at the project, way back in 2013, it has seen lots of new releases with features, bug fixes, and refinements aimed at appealing to a wide range of users. Some of the biggest additions landed in the 3.0 release, but we will also describe some other notable changes from version 2.1 up through latest version.
The first release of fish was made by Axel Liljencrantz in February 2005. Version 2.0 was released in September 2013, and 3.0 in December 2018. The latest version, 3.1.2, was released on April 29, 2020.
Prior to the 3.0 release, fish lacked a special syntax to express logical AND
&&) and OR (
||) operations. Instead, the
or commands were used
for such operations. These commands verify the previous command’s exit status
before acting accordingly. For example,
command1; and command2 expresses a
logical AND operation in which
command2 is executed if, and only if,
command1 returns an exit status of zero.
This syntax proved to be unpopular among converts from other shells where
operators such as
! were used to express logical operations
and it was the subject of several
discussions on the
project’s issue tracker. Due to popular demand, these logical operators are now
supported as of fish 3.0 to make it easier to migrate from other shells. It is
now possible to enter
command1 && command2 in the shell or in a script to
express the logical AND operation.
History and incognito mode
When a command is executed in the shell, it is inserted at the end of the
history file located at
~/.local/share/fish/fish_history, accompanied by the
timestamp of its entry. It is also possible to save a command to the history
without executing it using the Alt+# binding (introduced in version
2.3.0). It toggles the current command line between commented and uncommented
states. As with Bash and other shells, the up or down arrow keys can be used to
or backward in the history.
One nice feature for fish history is the ability to filter through the history
based on what is typed into the shell. Entering a few characters and then
hitting the up arrow key performs a history search for the commands that include
the typed characters. For example, typing
git and hitting the up arrow will
display only the commands that contain the string
Fish does not enter any command that begins with a space into its history file, essentially treating it like an incognito command. This often surprises users who are transitioning to fish from Bash or other shells that do not have this behavior; it is also easy to activate it unintentionally when pasting commands to the terminal from other sources. There have been several discussions in GitHub issues on whether to retain this behavior in future releases and how to make it more discoverable. As of fish 3.1.2, no changes have been made to this aspect of the shell behavior.
A new addition in fish 3.0 is the
--private flag that can be used to start fish
in private mode; it stops all subsequent commands from being logged in the
history file. This is handy for when a user wants to enter sensitive information
in a command. The
$fish_private_mode variable was also added for the purpose of
detecting if a script is being run in private mode so that its behavior may be
modified accordingly to respect the user’s wish for privacy.
Aliases and abbreviations
Like many other shells, fish provides the ability to define memorable alternate names (known as aliases) for commonly used commands. Aliases can help to eliminate a great deal of typing when working in the command line. There are two ways to create aliases in fish. The first involves creating a function wrapping a command:
The second option is to use the alias keyword, which is essentially a shell
wrapper for the function syntax above. When using this syntax, the
arguments string will be appended automatically.
The release of fish 2.2 brought support for
abbreviations to the shell.
These are similar to standard aliases, but expand inline to the full command
when typed. For example, a command can be shortened to
yul using the following:
yul is entered into the terminal followed by the space or
enter key, it will be expanded into the full command. By default,
abbreviations are stored to the universal scope, so they immediately become
available in all current fish sessions and subsequent ones as well. To make an
abbreviation visible in the current session only, use the (surprisingly named)
--global flag when creating it. This places the abbreviation in the global
scope which is local to the current shell. Abbreviations are generally better
than aliases because the full command can be seen before executing it, which
makes it easier to edit for a one-off change. They are also more suitable for
interactive demos or presentations because the instructor can use a shortcut
without obscuring the full command.
The default key bindings used by fish for moving the cursor around on the command line are from the Emacs editor. Examples are Ctrl+A to move the cursor to the start of a command, Ctrl+E to move to the end of a command, and so on. Fish 2.2 introduced a Vi mode for those who prefer bindings from the Vi editor. It supports command mode, insert mode, and visual mode bindings. Fish also provides shared bindings that are accessible regardless of your preferred mode.
If neither mode is sufficient for a particular edit, an external editor may be
summoned using the Alt+E or Alt+V shortcuts. The two
commands are synonymous; the editor is chosen from the first available of the
$EDITOR environmental variables.
Fish features an Emacs-style kill ring for blocks of text that were previously killed. For example, Ctrl+U cuts from the cursor position to the start of the line and inserts the text into the kill ring while Ctrl+Y pastes the latest value from the kill ring at the cursor position.
A change in Fish 2.4 is that any text cut with kill ring commands no longer overrides the system clipboard. This behavior was changed because it was a common source of frustration when pasting to the shell from external sources because cutting some text would override the previously copied text meaning that it would have to be copied again. Working with the system clipboard is still supported on Linux (X11 and Wayland) and macOS. Ctrl+X is used to copy the whole line to the clipboard (regardless of cursor position) and Ctrl+V pastes from the clipboard to the shell.
Web configuration tool
The web configuration tool, launched with
fish_config, provides a nice way to
customize the prompt style, color theme, and so on. An important security
enhancement landed in 2.1.1 which prevents a remote-code-execution attack when
running this web interface by using an authentication token to protect requests
and responding only to requests that include this token.
In addition, the behavior of this tool was changed slightly in version 3.1 by causing it to display a list of the commands it is executing, for debugging purposes. Other improvements include new theme presets, base-16 color options, prompt styles, and support for viewing, editing, and adding abbreviations.
Wrap it up
Fish was originally implemented in C but is now primarily written in C++. It does not follow any particular release cycle but major versions usually take a few years to come out. The best way to follow the development of the shell is through its GitHub repository and official mailing list. The changes that are being planned for upcoming releases are detailed on the milestones page on GitHub. An official Gitter channel also exists for community discussions.
Overall, the refinements being made continue the process of making fish easier and more convenient to use compared to other shells. It strikes a good balance between having useful defaults to get started with immediately and leaving room for extensibility and customizability. A tutorial is available for those looking to quickly get up to speed with the precise differences between fish and more traditional shells.