|
|
Subscribe / Log in / New account

New features in the fish shell

September 29, 2020

This article was contributed by Ayooluwa Isaiah

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.

[Fish shell]

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.

Logical operators

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 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 search forward 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 git.

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:

    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 $argv arguments 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 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.

Vi mode

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.

Clipboard integration

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.

[Fish configuration tool]

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.


Index entries for this article
GuestArticlesIsaiah, Ayooluwa


to post comments

New features in the fish shell

Posted Sep 29, 2020 18:18 UTC (Tue) by ibukanov (subscriber, #3942) [Link] (4 responses)

I am surprised that it took so long for fish with its focus on UI experience to implement || and && as shortcuts for longer ;or/and variants. These are not esoteric operations that are useful only for advanced scripting. I use them in bash in interactive session often. For example, git push && cd .. && git push when working with submodules or various make && run-resulting-executable.

New features in the fish shell

Posted Sep 30, 2020 17:54 UTC (Wed) by glasserc (subscriber, #108472) [Link] (3 responses)

I'm a long-time fish user who feels the opposite way. I really like the regular syntax of the fish shell language (no [[, then, fi, esac) and introducing special syntax for and and or detracts from that. The linked discussion on Github also has additional arguments in both directions -- for example, && and & function very differently despite their apparent visual similarity; but also, complicated boolean conditions in if statements in fish are a little clumsy because only the first command (until the first semicolon) is the condition, so && helps mitigate that.

New features in the fish shell

Posted Sep 30, 2020 23:19 UTC (Wed) by johannes (guest, #116140) [Link] (1 responses)

> also, complicated boolean conditions in if statements in fish are a little clumsy because only the first command (until the first semicolon) is the condition, so && helps mitigate that.

Surprisingly, a condition for if/while consists of a command plus a tail of and/or commands, see https://github.com/fish-shell/fish-shell/blob/master/src/....
This means you can write chained conditions like this:

if cheap-condition; or expensive-condition-part-1; and expensive-condition-part-2
# body goes here
end

Although as a developer I agree that && and || look better.
Using begin/end for grouping allows for more complex conditions.

New features in the fish shell

Posted Oct 1, 2020 12:36 UTC (Thu) by widowmaker (guest, #142307) [Link]

As developer, I disagree that && and || have better readability. Usually, too much special characters only make it worse.

New features in the fish shell

Posted Oct 2, 2020 23:21 UTC (Fri) by qlyoung (guest, #142338) [Link]

Allowing && and || massively increases compatibility with copy-pasting shell snippets on the internet into your shell, for those who live life on the edge.

New features in the fish shell

Posted Sep 29, 2020 19:34 UTC (Tue) by logang (subscriber, #127618) [Link] (14 responses)

I tried fish many years ago and the biggest thing I could not tolerate was the search feature described in the article. Bash has the standard Ctrl-R search which is so ingrained in my fingers that fish's lack of support for the shortcut made it unusable for me.

Also, the article is wrong about incognito mode. Bash does not add commands that begin with a space to the history and has done so for as long as I can remember. It's just not a feature that's well known -- I only found it by accident.

New features in the fish shell

Posted Sep 29, 2020 19:44 UTC (Tue) by skx (subscriber, #14652) [Link] (3 responses)

Bash does allows you to ignore history entries that begin with a space, but you need to set the HISTCONTROL variable to ignorespace.

New features in the fish shell

Posted Sep 29, 2020 19:49 UTC (Tue) by logang (subscriber, #127618) [Link] (2 responses)

Ah, "HISTCONTROL=ignoreboth" seems to be in the default debian-based bashrc file. Perhaps other distros do not set it by default.

New features in the fish shell

Posted Sep 30, 2020 13:39 UTC (Wed) by Paf (subscriber, #91811) [Link] (1 responses)

CentOS and SLES(I think, not 100%) both do. My impression is it’s standard.

New features in the fish shell

Posted Sep 30, 2020 22:27 UTC (Wed) by sjj (guest, #2020) [Link]

At least 25 years that I can remember...

New features in the fish shell

Posted Sep 29, 2020 19:47 UTC (Tue) by jake (editor, #205) [Link] (1 responses)

> Bash does not add commands that begin with a space to the history

hmm, it does for me (add commands that start with a space to the history) ... i haven't investigated why but it is not something i (knowingly) configured ...

jake

New features in the fish shell

Posted Sep 29, 2020 19:52 UTC (Tue) by dtlin (subscriber, #36537) [Link]

It's an option, HISTCONTROL=ignorespace or HISTCONTROL=ignoreboth will not save commands starting with space to ~/.bash_history .

New features in the fish shell

Posted Sep 29, 2020 19:54 UTC (Tue) by mathstuf (subscriber, #69389) [Link] (3 responses)

Hmm. I use Ctrl+R in zsh myself. I also have Ctrl+P which does a glob to match the history (rather than literal matches). But, I also use the Up searches for history with the same starting word and I add Ctrl+Up which searches the history for entries with the same text before the cursor. They all have their uses. Did fish really not have Ctrl+R (or what I have on Ctrl+P) before?

New features in the fish shell

Posted Sep 30, 2020 12:13 UTC (Wed) by andrewsh (subscriber, #71043) [Link] (2 responses)

Fish searches through history continuously without you needing to press Ctrl+R.

New features in the fish shell

Posted Sep 30, 2020 12:35 UTC (Wed) by mathstuf (subscriber, #69389) [Link] (1 responses)

Right, but that's only prefixes IIRC? How do you search the history for commands with words in the middle?

New features in the fish shell

Posted Sep 30, 2020 14:47 UTC (Wed) by ayoisaiah (guest, #141800) [Link]

It works regardless of the position of the word in the command.

New features in the fish shell

Posted Sep 29, 2020 22:05 UTC (Tue) by gus3 (guest, #61103) [Link] (2 responses)

My .bash_profile contains "export HISTFILESIZE=0". This allows each instance of Bash to have its own history, but it isn't saved on shell exit.

New features in the fish shell

Posted Sep 29, 2020 22:25 UTC (Tue) by mattdm (subscriber, #18) [Link]

You can just unset HISTFILE to get this behavior.

New features in the fish shell

Posted Oct 3, 2020 6:33 UTC (Sat) by marcH (subscriber, #57642) [Link]

Wow, why would you _not_ want to save your history to disk?!? That's where my entire productivity comes from, together with:

"\e[B": history-search-forward
"\e[A": history-search-backward

... in /etc/inputrc.

New features in the fish shell

Posted Sep 30, 2020 1:23 UTC (Wed) by zanchey (guest, #94250) [Link]

There's a number of differences in philosophy between the projects, but this thread has somewhat vindicated our strong opinions on configurability.

New features in the fish shell

Posted Sep 29, 2020 21:10 UTC (Tue) by nash (guest, #50334) [Link]

So for a shell which is designed to be user friendly there are a lot "surprising behaviours" listed. The &&, space to hide history and --global is local.

New features in the fish shell

Posted Sep 29, 2020 22:15 UTC (Tue) by areilly (subscriber, #87829) [Link] (2 responses)

I tried fish a few years ago but gave up after a month or so. There are some good ideas in there, around auto or semi-auto configuration, but what ultimately killed it for me was the "not Posix sh" syntax. All of the UI stuff was lovely, but I don't see that that has to imply a different shell language (and obviously things like ZSH have most of the UI loveliness and still mostly-sh compatibility). The thing that ultimately did it in for me was that I couldn't get it to behave sensibly around remote ssh commands (with fish as the login shell on the remote machine). I've come to the conclusion that sh is just a really nice language syntax. Particularly nice for its ability to express complicated things on one line.

New features in the fish shell

Posted Sep 30, 2020 5:21 UTC (Wed) by johannes (guest, #116140) [Link] (1 responses)

I think it's a fine choice to use fish interactively and sh for scripts.
The use case is different, so different tools are justified. The most used interactive commands work the same way in fish.
There are easy-to-learn fish equivalents for constructs that are commonly used interactively. If something is missing it can usually be implemented in a small function.
Supporting obscure features from other shells yields diminishing returns, but widely used features are happily added, like && and var=value.
Likewise, humans use different constructs in oral and written language, both languages co-evolve and adopt useful features from each other.

> All of the UI stuff was lovely, but I don't see that that has to imply a different shell language

True but it's much easier to implement consistent highlighting, indentation, completion and error messages if the language is syntactically simple. Other shells don't indent or highlight at all.

> I couldn't get it to behave sensibly around remote ssh commands (with fish as the login shell on the remote machine).

Yeah, that's one of the places where setting fish as login shell can backfire. It's often better to launch it in a different way.

New features in the fish shell

Posted Sep 30, 2020 10:31 UTC (Wed) by mathstuf (subscriber, #69389) [Link]

> Yeah, that's one of the places where setting fish as login shell can backfire. It's often better to launch it in a different way.

I agree. I use zsh almost exclusively, but my login shell is bash. I configure my terminal-launching keybindings and tmux to use zsh by default instead.

New features in the fish shell

Posted Sep 29, 2020 22:38 UTC (Tue) by miquels (guest, #59247) [Link] (2 responses)

There are more shells that are not POSIX compatible. One to keep an eye on is "nu shell", https://www.nushell.sh/ . Say what you will, it's interesting that other avenues are being explored.

New features in the fish shell

Posted Sep 30, 2020 6:11 UTC (Wed) by fwiesweg (guest, #116364) [Link] (1 responses)

Oh wow this one looks really cool! Every time I tried to work with structured data in bash I just gave up after five minutes and ran python, but nushell actually allows it without going insane! Need to give that a try instantly. If it works well, I'll say goodbye to awk, grep and sed in no time ;-)

New features in the fish shell

Posted Nov 3, 2020 15:52 UTC (Tue) by nix (subscriber, #2304) [Link]

Seconded. It's very strange at first sight, but it's a really interesting reimagining of the shell idea: even the bits that look crazy (ls is a builtin?!) make sense later on when it becomes clear that you can do things like cd into tree-structured text files (a branch of a JSON file, say) and ls them and edit them on the fly :)

I don't think it's a good login shell but for popping into to dig around at structured text it's ever so much nicer than sed/awk oneliners a lot of the time.

New features in the fish shell

Posted Sep 29, 2020 23:13 UTC (Tue) by randomguy3 (subscriber, #71063) [Link]

While I don't use the fish shell, I very much appreciate that it has championed interactive-shell features that have since been implemented as zsh plugins, making my shell experience so much nicer than it would otherwise be.

New features in the fish shell

Posted Sep 30, 2020 0:28 UTC (Wed) by flussence (guest, #85566) [Link] (8 responses)

> 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

Huh. I'd gotten so used to putting HISTCONTROL=ignoreboth in .bashrc on every system that I forgot the space behaviour wasn't a default there.

New features in the fish shell

Posted Sep 30, 2020 13:42 UTC (Wed) by Paf (subscriber, #91811) [Link] (7 responses)

May I ask why? I dislike the feature and am glad I now know how to turn it off. I’m curious what use people have for it.

New features in the fish shell

Posted Sep 30, 2020 14:09 UTC (Wed) by randomguy3 (subscriber, #71063) [Link] (1 responses)

For me, I don't use the history suppression very often, but occasionally I want to use a command that requires, say, passing a password as an argument (not ideal, but sometimes unavoidable), or something that will pollute history searches (which I make heavy use of). A leading space is something I rarely do accidentally, but is easy to do and easy to remember when I want it.

New features in the fish shell

Posted Sep 30, 2020 20:38 UTC (Wed) by mathstuf (subscriber, #69389) [Link]

My pattern for this is to put the token/password in a variable whose assignment is hidden in the history with the leading space. The command itself is usually of value in the history.

New features in the fish shell

Posted Sep 30, 2020 20:06 UTC (Wed) by szm (subscriber, #100120) [Link] (3 responses)

In addition to the sensitive information / password use-case already mentioned, I've picked up the habit of excluding potentially catastrophic and destructive commands like, let's say,

rm -rf ./*

or dropping database tables, etc. from the search history. Before learning about history suppression in my younger years (i.e. back when I tended to be prone to getting nervous during an incident with a critical system or when I sometimes would grow impatient while working over high-latency ssh connections), I've had several jump-scares when, by "typing ahead" not only commands but retrieving items from the history with the arrow keys, found that I accidentially ended up with the "interesting side-effects if run here and now" kind of command. Luckily always before hitting enter, but still.

It's not a fool-proof system, but I find it quite useful in the "better safe than sorry" kind of way.

Cheers,
szm

New features in the fish shell

Posted Oct 1, 2020 0:02 UTC (Thu) by Paf (subscriber, #91811) [Link]

Interesting, thanks!

New features in the fish shell

Posted Oct 3, 2020 6:44 UTC (Sat) by marcH (subscriber, #57642) [Link] (1 responses)

> rm -rf ./*

Agreed 200%: I recalled by mistake commands like these from my (crazy long) bash history once or twice and now I'm trying hard to never let them get there in the first place.

Another trick I use (better safe twice than sorry) is this:

rm -rf ../current_directory/*

With completion it takes barely longer to type and it greatly reduces the chances of that command doing anything if recalled by accident.

Finally, there is of course:

mv * ~/Trash/

Only the last one would probably have stopped me from recursively deleting the target of a symbolic link while thinking I was just deleting the link itself...

New features in the fish shell

Posted Oct 3, 2020 17:51 UTC (Sat) by jo42 (subscriber, #59640) [Link]

Zsh has the helpful feature to filter history entries. Defining the function zshaddhistory to stop some commands going into the history file:

zshaddhistory()
{
# Don't save run-help and kill commands and commands run in bad-stuff
[[ $1 != (run-help *|kill *|bg|fg|cd|reboot|halt) && $PWD != $HOME/bad-stuff/* ]]
}

New features in the fish shell

Posted Oct 3, 2020 6:46 UTC (Sat) by marcH (subscriber, #57642) [Link]

> May I ask why? I dislike the feature and am glad I now know how to turn it off. I’m curious what use people have for it.

You could start by explaining why you dislike the feature, I'm curious :-) Lots of copy/paste?

New features in the fish shell

Posted Oct 1, 2020 11:38 UTC (Thu) by nelljerram (subscriber, #12005) [Link] (1 responses)

Is there an option for treating aliases as abbrevs, i.e. expanding them when typed? That feels like it would be nice. You'd still need the normal alias logic as well, for scripts using the aliases.

New features in the fish shell

Posted Oct 9, 2020 2:06 UTC (Fri) by beren (guest, #142429) [Link]

Fish does support abbreviations. I frequently use them. They’re the best of both worlds. Quick typing for me, with full fidelity for history and sharing with others via screen, type, asciicasts, etc.

https://fishshell.com/docs/current/cmds/abbr.html

New features in the fish shell

Posted Oct 3, 2020 6:51 UTC (Sat) by marcH (subscriber, #57642) [Link]

> The default key bindings used by fish for moving the cursor around on the command line are from the Emacs editor.

More like the readline bindings used in many other command lines and not specific to Emacs.


Copyright © 2020, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds