As a long-time power user of fish for 6+ years, I cannot live without it. It's easily in my top 5 most game-changing upgrades to my dev environment. (up there with a clipboard history manager and TabNine for code autocompletion)
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
The best part about fish is you don't have to configure it much to be productive in it. It is really nice that the fish maintainers think hard about what should be configurable, and what sane defaults should be. This is not as common as it should be in OSS. Contrast with zsh, which has a billion knobs to tweak, and the consensus is that everyone should install a huge "community dotfile framework" (whatever that means) consisting of tons of opaque aliases and settings, some of which might make your shell startup lag.
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:
I ended up implementing my own background process management for fish here, it uses bash to fork a subshell with fish inside of it, which seems to solve all the problems I encountered.
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:
Very true. I have been using fish for the last five years without really learning the shell. The auto-complete itself feels so good and makes me productive.
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)
Fish functions are just gorgeous, and what made me drop Zsh like a hot potato. Suppose you want to make an automatically loaded (that is, not defined in the shell's rc file) function called foo. Here's how you do it:
- 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.
> Now, create an autoloaded function in Zsh or Bash without looking at a man page.
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."
That's what I'm talking about. I'm super comfortable reading the man pages for things, but if a tool wants to take over all the boilerplate and do things for me, awesome! Sure, I can add a function by editing rc files. That doesn't scare me one bit. But... why? There's a lot to be said for convention over configuration.
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.
Oh please. The exact same thing can be said for fish. How did the parent commenter know to create a file named ~/.config/fish/functions/foo.fish? How did the parent commenter know to define a function inside that file?
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.
I've been using fish for longer than I can remember, but I almost never write fish functions. The out of the box experience is already much better than bash/zsh (out of the box, not including plugins/etc).
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.
> 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)
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....
Thanks for the link. Makes sense that if Fish doesn't fork itself and isn't multi-threaded then that would be a difficult feature to implement. I had the same consideration right at the conception of my project: fork or multi-thread? I went with the latter. But my shell diverges quite a bit from the typical design a shell would take so there's a lot of reasons it's sub-optimal compared to the excellent work the Fish guys have done with their shell.
Clipboard history manager (I use Alfred's on macOS), TabNine, Fish Shell, ripgrep/ag, and SublimeText's jump to definition & "show usages" for all symbols in the current project.
I've a similar collection of "functions", but I implemented them just as plain bash/sh scripts in my ~/bin. I think putting your functions into regular executables on the path would have been more portable. That way you wouldn't need to call them from a fish shell to run them (you can still use fish scripting language if you like).
To preface — I love Fish — "Finally, a command line shell for the 90s" is an apt description. I use it every day.
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)
This is the point of Oil -- having a smooth upgrade from bash. The interactive shell ended up being more work than I anticipated. So I'm looking for people who want to run with it either as a separate project or part of Oil.
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.
It's a chronic problem on work projects that people write shell scripts without a shebang operator at the top. Obscure error messages are usually how I find out someone is using zsh, fish, or some other shell.
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.
One way I force people (mostly myself) to include shebang lines:
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.
you can source a file that contains a shebang in most (all?) shells assuming it contains code written in the same shell language. I.e. a bash file can't source a fish file and vice-versa.
I wish someone had recommended fish to me as a beginner. When I discovered it I was finally able to write some aliases and scripts without copy/pasting, overdoing it by resorting to a real programming language, or wasting an entire day trying then giving up. Concerning bash instructions, it's not that hard to translate them imo, or you can just use bass or just pop into bash for a second.
> Or error messages which return translated commands?
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`.
Good point on the loop, I hadn't thought about that, thanks for correcting me.
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.
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
Bash is definitely seen as the "Linux shell", but most users of non-Linux Unixes and Unix-likes don't use Bash. macOS, for instance, now uses Zsh out of the box (although most Bash one-liners still run unmodified in Zsh).
But Linux is the majority of the Unix-like market, so it (and therefore Bash) dominates.
macOS just recently switched to zsh as the default and doesn't change the shell for existing users so I imagine it is likely the majority of macOS users are still using bash.
True, although it gives you a pretty prominent notice that Zsh is now the preferred shell when you start Terminal for the first time after updating to Catalina.
Oil is more focused on making shell scripting nicer, Fish is more focused on making shell interaction nicer. Both are cool projects, just slightly different focus.
I don’t think this is such a big deal. Every programmer needs to become sufficient in bash because odds are you’re going to log into another computer which only has bash or csh, and likely you need to modify someone’s bash script. It’s probably best for beginners to learn bash first, and for intermediate users to switch to fish once they understand the concepts.
It actually doesn't come up that often. A lot of times you can just either A) paste one line at a time or B) use double quotes.
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.
Fun story. Couple of years ago, a few colleague's and I were casually chatting at our desk about fish shell. When suddenly we hear someone a few desk away saying with a big smile: I wrote that!
Many of the comments in this thread refer to the sheer inertia of millions of LOC of bash script in the wild. This seems to be the main reason why Oil shell[1] aims to be "an upgrade path from bash to a better language and runtime".[2]
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.
This, especially the long-awaited introduction of logical operators (&&, ||) is most welcome.
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!
I tried to use fish for a while and ended up giving up and going back to bash, mostly for one (somewhat irrational) reason: fish kept recognizing bash-isms and yelling at me about it.
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.
I get the sentiment, but not sure I agree with the "either interpret it, or don't" part - it sounds like you are essentially saying the scripting should either match Bash completely (and thus lose out on the more modern syntax) or not offer any kind of helpful error to users. Or perhaps support both types of syntax?
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
I've been using fish for a long time from the 1.x branch, after a long time using bash, and tcsh before that in the 90's. Before that the primitive CMD and DOS.
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.
fish-shell dev here. Sounds like you have been using it longer than me!
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!
> (terminals don't publish their colors so the defaults have to work on light and dark)
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.
The only dependency the web configuration tool should bring in is Python, which is already an optional dependency for the manual page completion generator. You can install and run fish without ever running the web configuration.
> They moved away from the daemon, and variables no longer get propagated across shells.
Universal variable changes should be propagated across different fish processes. However, it looks like the maintainers are questioning whether they should live on.
Many years ago, before I discovered fish, I tried the loved by many zsh shell, but found myself spending too much time messing with the configs to get it how i wanted.
On my quest to find something better and avoid coding my own, I discovered fish.
fish is easily one of my all time favorite linux cheats to increase productivity, without spending hours tweaking configs.
It is very usable out of the box, and includes a web-ui mode to make easy basic customization stuff like theme and PS1 var.
Finding/re-using command history is a breeze, you can
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've used fish in the past but went back to zsh. IIRC fish broke a bunch of times between versions and the maintainer feedback wasn't great. The maintainers of course don't owe me any of their time, so I'm not mad about it, I just don't use it anymore because I need my shell to work reliably every time I open a terminal. (I don't remember the precise problem but I'm sure I could go find it.)
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.
The inputrc change is nice, but not quite the same as what fish does.
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)
I agree, although otoh, the inputrc change is not specific to bash. It is useful for any cli that uses readline (mysql, python prompt, pgcli,...). Other useful inputrc settings I have in mine :
# - 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 on
One of the things that really bug me out about fish shell is how it completes history. If you type the beginning of a command, you can use the arrows to cycle through all matching history items. All items BUT THE LAST ONE. That one you have to complete with ctrl-f.
And 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.
I gave fish a serious try last year, and really loved the command-line completion, but the vi mode editing was a deal-breaker. It's minimally usable, in particular it doesn't support command combinations like dt/ ct/ ; d0 etc... In the end I found a history completion plugin for zsh that worked as well as fish, and ended up going 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.
To reprise a previous comment, I think vi mode suffers because it's a relatively niche feature - none of the current committers use it as far as I know, and pull requests to improve it are relatively infrequent. 1.8% of the pull requests into the (not yet released) 3.2.0 are for Vi mode, which is a slight increase on previous milestones, and includes support for dh, dl, c0, cf, ct, cF, cT, ch, cl, y0, tilde, ci', ci", yi', yi", di' and di".
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.
Sure, understandable and reasonable. Just wanted to mention it for others that may care. Fish has some great stuff in there. But, in my case, 30 years of vi muscle memory was hard to blunt.
I was misremembering, it was the combination with motion commands: dt/ ct/ ; d0 -- if these work now you probably want to provide feedback on the issue I mentioned above, because it's still marked as open.
dt/ cw and d0 work, but ct/ doesn't. Seems like maybe they've hardcoded certain command-motion combinations, but not actually done it "properly." FWIW, it acts enough like vi that I never noticed until today.
Fish shell is simple great.
I use it for many years on my daily development on Linux/Mac without regret it.
The way how it speeds up my software development process from the command line is invaluable.
However I still use Bash for writing production scripts on my servers for different reasons like compatibility, requirements, etc. But when I get my server via SSH, Fish rocks also there.
I think Fish is fantastic, but just can't use it because so many things rely on either Bash or Zsh. I've settled for a modest ZSH setup with Prezto and I'm pretty happy.
In my years as a dev I haven't found many true dependencies on Bash/Zsh. For Ruby, rbenv and other solutions worked. For Python, there was virtualfish to make virtualenvs work properly. Although now pyenv works out of the box with Fish. Other than that, simply adding a shebang to scripts is sufficient.
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.
I've been using fish for years now and cannot remember the last time something broke because it required bash but was run by 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.
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.
This is a great idea, and one that I think would fit my workflow very well!
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.
I've been using fish as my default shell for ~3 years now. The faint gray history auto-complete / search that appears when typing commands alone is a killer feature. urxvt + fish + ranger + sauce code pro font = me loving my terminal experience a ton. Thanks fish devs!
I find it has two advantages. One, being quite a sophisticated auto-complete system. I haven't seen anything nearly as polished. The other advantage is it's easy to learn and configure. You can read the short manual and you'll know about every feature and keyboard shortcut that exists.
Fish autocomplete seemed like magic when I first started using it. I does things like autocomplete file paths on the android side of adb sync commands, autocomplete on docker container hashes..
I am a longtime zsh user and tried fish earnestly for a month or so, but gave up because I could not figure out how to ignore certain patterns while auto-completing filenames. For example, I typically edit tex files and I don't want any of the temp files to be suggested as autocomplete suggestions. In zsh, I can write
It’s a sane scripting language. It encouraged me to automate simple tasks, create handy functions etc. I don’t have to google the for loop syntax every time I need it.
oh-my-zsh can be quite slow on very powerful machines for very simple tasks. Also having a shell default to most of the features you need makes docs simple compared to the million flags of zsh
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 ;)
It lacks "ctrl+r" because it does history search even better than bash. It shows auto-suggestions based on your history. I find ctrl+r when I'm in bash kind of annoying, and not as good at searching.
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.
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