New Features in the Fish Shell
lwn.net
lwn.net
Over the years I've amassed hundreds of fish functions for common tasks on my machines, https://github.com/pirate/fish-functions. I loved it so much I started using it to write devops/deployment scripts instead of bash. That was a mistake.
It has some serious limitations as a scripting language, namely lack of proper subshell support and background process control. The relevant issues have been open for years with no clear resolution in sight. (which is fair, these are very hard problems and it's an open-source project with finite resources)
That's fine though, it's still my favorite interactive shell for use in a Terminal. I just make sure to write any script longer than a few lines in Bash. https://github.com/pirate/bash-utils
More to a specific point: I haven't had much of an issue with fish's subshell/backgrounding control. That doesn't mean that there aren't issues, just that my interactive use doesn't trip into them.
I will note that you can write an async git prompt using nothing but fish itself, which I consider an advanced use case for a shell. Check it out:
https://github.com/pirate/fish-functions/blob/master/backgro...
https://github.com/pirate/fish-functions/blob/master/progres...
https://github.com/pirate/fish-functions/blob/master/signal....
https://github.com/pirate/fish-functions/blob/master/fork
Usage:
background progress_await compiling_task_finished
g++ ... some slow command
signal compiling_task_finished
This allows the progress bar to truly run at the same time as the g++ command and receive a signal from the fg process when it's time to complete, something a simple & does not let you do in fish.I've collected more details on Fish's issues here for anyone interested:
Confession: I haven't taken pains to learn any shell after that. Almost similar to why I never took to try out VSCode after getting used to Sublime Text. So many demos, videos etc. quite tempt me to try out VSCode but still haven't ever got to it)
The only thing that I took note was to install https://github.com/oh-my-fish/oh-my-fish every time I setup a machine.
Would be great to know of any quick to learn fish-hacks or fish-for-dummies resources
* get comfortable with stdin/stdout/stderr syntax (and redirection)
* get piping down pat. It's so useful.
* practice using &&, ||, and ; to sequence commands
* know how to use ENV=value to override env vars, and understand how env vars work
* yak shave a bit and make some aliases/functions in your shell based on your usage patterns
From here, it gets esoteric pretty fast, no matter what shell you're in. But you have enough concepts to figure out you need from there.
I also prefer the basic syntax for things like for and while looks on the command line, the way they get formatted. With bash I always had to look up the syntax because I didn't use it much. Fish, I barely have to look up things because they are pretty intuitive, for the most part.
Also, no adding `export X=Y` to your .bashrc because you can just `set -U` and it automatically saves it between sessions.
- Make a file named ~/.config/fish/functions/foo.fish
- Inside it, define a function named "foo"
That's it. Now when you open a new shell and try to run the command "foo", Fish will look for the file named foo.fish in that directory, load and execute it, then call the foo function from in it.
Now, create an autoloaded function in Zsh or Bash without looking at a man page.
There are a million little niceties like that where I'd assumed that a certain task had to be complicated because every shell I'd used before had made it complicated, but then Fish came up with a nice convention for making it simple. Want to make a function to dynamically set your shell's prompt? Create a function named "fish_prompt" in the file ~/.config/fish/functions/fish_prompt.fish. Ta-da - turns out it doesn't have to be a pain in the neck to do that.
I completely agree about using it as a scripting language, though. It's great for making functions for your interactive shell, but stick with sh or bash (or Python) for writing more sophisticated stuff.
for fname in $(ls ~/.config/zsh/functions); do source $fname; done
:)will prevent issues with special chars and spaces in filenames
GP is talking about JIT loaded functions: 'that is, not defined in your shell's rc file'.
For zsh:
- Make a file named ~/.config/zsh/functions/foo
- Inside it, define the body of the function for foo
- Add ~/.config/zsh/functions/foo to $fpath with "fpath+=~/.config/zsh/functions"
- Declare foo with "autoload -Uz foo"
> Want to make a function to dynamically set your shell's prompt? Create a function named "fish_prompt" in the file ~/.config/fish/functions/fish_prompt.fish. Ta-da - turns out it doesn't have to be a pain in the neck to do that.
To do the same in zsh:
- define a function (can be autoloaded or not) named prompt_foo_setup to change your prompt
- add the following to your zshrc: "autoload -Uz promptinit; promptinit"
Now you can easily change to your custom "foo" prompt by running "prompt foo".
There are many valid points which make zsh (or bash) hard to use out of the box, but neither of the points you've raised are one of them. One can easily do both without "looking at the man page."
How do you know which flags to autoload to use without reading the docs? How did you know to call autoload?
The point is, it's trivial to create an autoloaded function in both fish and zsh. You don't have to look at the man page each time, which is what was being implied in the comment I was responding to.
But to answer your question, you never need to call autoload with flags other than "-Uz" 99.99% of the time. So the idea that you have to consult the manual each time to figure out the flags is plainly not true. As for the fact that you have to call autoload to bring autoloaded functions into scope, what else did you expect? Fish's behavior of bringing undeclared functions into scope isn't exactly intuitive either.
For context, for a while I was the FreeBSD port maintainer for shells/bash-completion. I'm (too) familiar with the plumbing of various shells. I can do all the manual work myself, but there are lots of things I'd rather be doing instead.
funced foo
funcsave foo
funced will either allow you to edit it inline, with a clever multiline system, or through your $EDITOR.funcsave will record the file to the place you want once you're happy with the changes.
Which means you can funced as many times as you want on both new and old alike until you're happy with the function.
funced foo
Then edit your function in the editor, save and close it, and then: funcsave foo
to make sure it's there in the future sessions. Without that second step you can create one-time helper functions for the active session.You say that but I'd been writing a shell in my spare time and I solved those problems over the course of a few weeks. For me though, they were important problems to solve because few other lesser mainstream / alternative shells addressed those problems and thus they became all the more tantalising problems to solve. In Fish's case, they might be lower priority jobs.
Unfortunately though, I also broke job control support again earlier this year and haven't had the spare time during the pandemic (my kids have been understandably more demanding of my time now that I'm working from home) to fix it. So I can't demo that particular feature as working. As an aside, this is also a good lesson to everyone to write robust tests....
# these behave the same in bash but differently in fish
some_command & # this works
some_function & # this does not
The relevant issues are listed here if you're curious about why it's difficult to implement this in Fish: https://github.com/pirate/fish-functions#issues-with-fishJust set up TabNine, what are the other 3?
But I haven't managed to recommend it to beginners. There are so many bash instructions out there, and translating between bash and fish isn't easy for a beginner.
That's a great shame and missed opportunity, because beginners would in particular value a nice shell. The shell is often one of the harder tools to learn — e.g. I find beginners are more comfortable in a Jupyter Notebook than they are the shell.
I'm not sure whether there's a way of combining fish's ease of use with a notion of compatibility — maybe a "bash mode" for beginners, which accepts bash commands? Or error messages which return translated commands?
(I recognize not all commands can be translated, but all of those that would be run by a beginner can be)
"Xerox Alto"
https://www.computerhistory.org/revolution/input-output/14/3...
Having grown through the UNIX adoption in the enterprise, it kind of feels ironic that nowadays bash is kind of seen as the UNIX shell, and in those days it was just one among many possibilities to configure on /etc/passwd
But Linux is the majority of the Unix-like market, so it (and therefore Bash) dominates.
Fish imho offers superb usability, wouldn't want to miss it.
I fix what I can, but it's like mopping up water during a rainstorm. Yes it's better than doing nothing, but also there will be more in twenty minutes so don't make any plans.
Have a scripts directory in my repo that mixes shell and python scripts with no file extensions and executable bits set. If I don't put a shebang, it just doesn't run.
Of course, this requires you to have firm control of code style policies.
It would be bad.
Fish does this in some cases:
~> echo $(true)
fish: $(...) is not supported. In fish, please use '(true)'.
echo $(true)
^
> (I recognize not all commands can be translated, but all of those that would be run by a beginner can be)Not all of them, unfortunately.
Consider `while true; do something; done`. Fish interprets this as an unclosed while loop, where `do` and `done` are ordinary commands. So if you enter it you don't get a syntax error, fish just waits for more input until you enter `end`. The same goes for `if` and `for`.
On the error messages, I was thinking even clearer for beginners, giving them the whole statement, to avoid uncertainties around where the quotes should be included in '(true)'. Maybe even a shortcut to paste the corrected line in their terminal.
echo $(true)
^
fish: $(...) is not supported. In fish, please use '(true)', like:
echo (true)
Alt+r will insert this line in your terminal.But what I do is I run fish manually on top of bash. If I have an issue, I just type exit and then try to paste the commands in again. Then when I am done I restart fish.
http://www.oilshell.org/blog/2020/02/recap.html#fish-oil-is-...
Another option is to link Oil as a C++ library into another shell, which is starting to become possible. Oil handles all the difficult language and compatibility issues, and encapsulates them, so it's a great complement to someone who only wants to work on the interactive shell.
Even though it cleans up many legacy warts, Oil runs thousands of lines of real bash programs: https://github.com/oilshell/oil/wiki/Shell-Programs-That-Run...
Posts on the interactive shell: https://www.oilshell.org/blog/tags.html?tag=interactive-shel...
I think it's fair to say "If it doesn't work in fish, just type `bash` to enter a bash shell and try again."
We were sitting next to Axel...
I wish them luck.
That is nearly "done" for Oil, as it runs thousands of lines of real bash scripts.
There's a big list of known and mostly trivial differences here: https://www.oilshell.org/release/0.8.1/doc/known-differences...
If you're a bash user and you want your scripts to run under Oil, I recommend testing it! If your script doesn't run, you'll probably get a better error message than bash gives you.
Or you might motivate a change the OSH language (a cleaned-up bash). It's easier to change now than later.
I'm still looking for help too:
http://www.oilshell.org/blog/2019/12/09.html#help-wanted
https://github.com/oilshell/oil/issues?q=is%3Aissue+is%3Aope...
https://github.com/oilshell/oil/issues?q=is%3Aissue+is%3Aope...
In the past I used bash then zsh then migrated to fish and not looking back. If you work in a shell a lot I can't recommend it enough; it will boost your productivity. Especially with tons of cool extras like oh-my-fish.
Huge thanks to all the contributors; keep up the good work!
Clearly there's a code path to recognize the thing, so why not just do it? It already knows what I want, why post a message instead? Either interpret it, or don't.
Personally I think it's fine to help guide new users to the new syntax without directly supporting it - this keeps Fish scripts from all devolving into the (subjectively ugly) bash format. It's like a graceful deprecation warning.
Edit: although I do think ceding on the logical operators (&&, ||) was a good move since that one is so fundamental
What happens if you loose data because of a wrong assumption?
I like much of what the new crew (who took it over) have done, but after installing it on a new machine recently I realized I didn't like their web configuration and some defaults. Which I almost never use, but a newbie would.
First, terminals have much improved in the last three decades. There's no obvious reason a curses-like app couldn't take the place of the web app. Configuring the shell from the web is rather gratuitous and weird IMHO.
A second, minor concern is the use of blue hues in their syntax highlighting defaults. Blue on black is rather unreadable, hard to see on its own, weakest of the colors due to eye sensitivity. It's also bad at night-time. I'd like to see a more neutral/warmer color palette for the default.
I have other nitpicks, such as their docs are not good enough on how all the types of variables work, and why you pick one or the other, for example. They moved away from the daemon, and variables no longer get propagated across shells. That was a neat feature but they removed it around the time they instituted the web server. I don't really get those design choices, but there's still no friendlier shell.
Universal variable changes should be propagated across different fish processes. However, it looks like the maintainers are questioning whether they should live on.
We'd love to do a curses version of fish_config. I think you're right the default colors could be warmer and still work on light backgrounds (terminals don't publish their colors so the defaults have to work on light and dark).
Variables are still instantly propagated, it just uses fifos instead of a daemon!
Hi. There are actually some possibilities there, but it is not entirely reliable. Examples are xterm sequences and the COLORFGBG environment variable. Some terminals can be assumed to be dark such as the linux/bsd console or now vintage hardware.
Windows is most often dark, but there is an API to ask as well. However, I don't think fish works there. Perhaps from LSW.
Sounds like having default colors closer to medium gray is easier.
The web configuration bring in a hell lot of dependencies. Please make it a separate project.
Also if the readline part can be extracted to a separate executable, then it will be amazing. Imagine a fish like completion with psql. history -c curl # Return history that contains (-c) the word 'curl'
It's one of the first pieces of software I install to new Linux desktops.
I still prefer to keep my servers bare, thus I use the default bash shell there.I now use zsh with zgen and a smattering of modules. It works fine, doesn't have the issue that you have to first translate every snippet you find to your new shell, and it's still easy for the newer shell users in your life to use.
> One nice feature for fish history is the ability to filter through the history based on what is typed into the shell.
Add this to your .inputrc
## arrow up
"\e[A":history-search-backward
## arrow down
"\e[B":history-search-forward
> Fish does not enter any command that begins with a space into its history file, essentially treating it like an incognito command.Add "HISTCONTROL=ignorespace" to your .bashrc
> 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.
run unset HISTFILE
If I type a part of a previous command in and then press the up arrow in fish it will only cycle through history records that contain that as a substring (which is really the killer part of the feature).
(Yes I know you can do similar things in bash but you have to press other keys to put it in the history search mode)
# - when performing completion in the middle of a word, do not insert characters # from the completion that match characters after point in the word being # completed
set skip-completed-text on
# - displays possible completions using different colors according to file type. set colored-stats on
# - show completed prefix in a different color set colored-completion-prefix on
# - jump temporarily to matching open parenthesis set blink-matching-paren on
set expand-tilde on
set history-size -1
set history-preserve-point onAnd the worst thing is, this behavior is completely intentionally [0]. For some time I used a patched version of fish, but it was just too inconvenient and I went back to zsh.
The vi mode issue seems pretty hard to resolve, like have to completely reimplement the editing hard. You can, as an alternative, drop to a real editor if you need a real editor for the command. Here's the issue related to it: https://github.com/fish-shell/fish-shell/issues/4019
It's very interesting, but I'm pretty dead set on vi history editing, so it wasn't for me.
(Edit to update the commands it has issues with)
I don't think it helps that it's this huge target area which (the small number of?) users use a slightly different 10% of, and it can be quite complex to integrate new features into existing editor state.
set fish_greeting
function fish_prompt
echo (set_color green)(prompt_pwd)(set_color normal)'> '
end
edit: also there is a change that didn't get mentioned: fish now accepts `A=1 echo $A` for instance without using `env A=1 echo $A` like at some pointThe only thing I leave the default banner on is fish.
I laughed so hard when I read their motto some years ago that I had to try it. I use it mainly for the nice autocomplete and write scripts in bash ...
It is nice that they added "&&" for "and" etc. It was quite annoying until I got used to it.
That being said, I don't go and convert the shell of all my AWS instances to Fish. I just keep my local shell as Fish.
One thing I do differently than most is I don't make fish my system-wide default shell. I leave that as whatever the system default is. Instead I just make fish the default shell within the terminal emulator I use.
Never had an issue with it, and it is much easier to setup as well.
You can also set Fish to start up after bashrc (or whatever), so that you don't have to translate all your startup stuff.
The one thing I haven't been able to get it to do is to define and export environment variables properly..
So I typically open the terminal in Bash, do whatever sourcing bash scripts that set up environment variables, or do something like that by hand, then run fish.
Kudos to the developers for building a great productivity tool. No tool is perfect, fish has its warts but it's made me much more productive.
A lot of tools add bits to .profile/.bashrc/.bash_profile so this allows inheriting that.
I use tmux and if has an option for setting the default shell and that’s where I set it.
Open terminal, loads bash with it’s environments, then tmux loads fish.
I've tried fish in the past and loved it, but moved back to zsh when I realized that writing my personal scripts in fish essentially meant that I wasn't able to share them with colleagues.
Every once in a while I have to sub to Bash, but it's very rare.
zstyle ':completion:::(vim|nvim)::files' ignored-patterns '*.(aux|dvi|log|thm|idx|pdf|rel|out|tuo|tui|tuc|tmp|mpo|mpb|mpd|1|keep|pgf|fls|gz|fdb_latexmk)'
(yes, tex generates so many temp files!) I couldn't figure out how to do something similar in fish
Combine it with that idea of "prefix your local scripts with a comma" and it seems a neat way to save typing.
Anything you use on ZSH that you’re not seeing?
I'm sure it uses inputrc or similar, giving you a thing like:
$if mode=emacs
"\e[A": history-search-backward
"\e[B": history-search-forward
$endif
aka, type "fish" and press up arrow to only go through history that starts with "fish"also, how would you configure fish to use something that doesn't lean on arrows? ^r has its own useful power that can be separate from my use-case of arrows mentioned above, if not just bc you don't have to move off the homerow ;)
edit: this originally said ^D, which is EOF, not autocomplete :)
https://github.com/fish-shell/fish-shell/issues/602
And to clarify, I understand Fish has autocomplete as good or better than bash but not having the keyboard shortcut as ctrl-r is what's making it hard to get accustomed to since I jump around servers where only bash is available and have to use ctrl-r extensively.