Welcome to LWN.net
The following subscription-only content has been made available to you
Free trial subscription
Try LWN for free for 1 month: no payment
September 29, 2020
This article was contributed by Ayooluwa Isaiah
Fish (the “friendly interactive
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
look at the project, way back in 2013, it
has seen lots of new releases with features, bug fixes, and refinements
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
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
and and 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 &&, ||, and !
were used to express logical operations and it was the subject of several
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
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
function gc git commit $argv end
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
string will be appended automatically.
alias gc="git commit"
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:
abbr yul "yarn upgrade --latest"
Once 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
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
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 $VISUAL or $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
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.
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.
Did you like this article? Please accept our
trial subscription offer to be
able to see more content like it and to participate in the discussion.
(Log in to post comments)