So somewhat unique experience. I'm a designer. I code. React and css mostly. I do use Vim which I guess is weird for a designer.
I love Fish. I'm likely not their target audience.
I've been using it for years. Since the early days in 1.x land for sure. The homepage has never changed and I still laugh at the tagline. I find it's auto-completion, history and niceties indispensable. I'm the person who asks you what the command is to rerun the tests. With Fish I never have to ask you again. I just remember part of it, and suddenly I've got it.
I find its scripting language much simpler to follow than bash. I don't have a lot of scripts, but the ones I do are easy to manage. The only hiccup I get into is when I have to look up something on stack exchange, and of course the example is in Bash. These days though, with Bass and fisherman and so many other tools, i have options.
Years ago I would explain to other code friendly designers, I'm weird, don't use this stuff. Go grab zsh. Lately though it's gotten very friendly. Really the only downside for a light scripter like myself is that need to convert bash examples to fish problem. Beyond that I feel it's actually a much nicer shell for new to terminal folks.
Anyways, just an anecdote to add to the pile. Thank you to the devs that have supported it over the years.
fish is my preferred interactive shell (I have window 0 on screen set to be fish), I still write all the scripting I do in bash, because I know it's probably already installed out of the box.
Until you raised this point I didn't think if fish as something you'd script with.
I really love the syntax and performance of fish shell, I had a few bash scripts that were used to manage the system volume notifications and power/battery information, as I use fish as my interactive shell, I ported them over to fish and tried to compare the performance, and to my surprise the fish variant was faster. I decided to rewrite the random wallpaper script for sway in fish too and it runs much faster then the original python snippet I got from swaywm's issues[0] (link to original python script[1]):
I really love fish shell and find its multi-line input extremely valuable, I think it has a much saner syntax (I have no meaningful experience writing bash scripts), if you are like me in this regard I highly recommend writing your personal scripts in fish instead and if you are worried about posix compliance, it is not that different from a bash script with bashisms in that regard.
yeah agreed. If you have trouble understanding how it could be better just install fish and try it for 5 minutes and you'll see what we mean. There are attempts to emulate some of it in zsh, but it's still not as good as what fish comes with out of the box.
Because we are able to extract useful information from colorized output, being as it is an extra dimension of information output; I for one don't get an urge to pass a sort of of societal judgement of the high/low artistic worth of the use of color which may further increase efficiency. ¯\_(ツ)_/¯
Color is indeed very useful for terminals. But it seems to me that fish takes the use of color to an exaggerated, very unpleasant, extreme. It feels overwhelming to my senses. Like having blinking text here and there. It fills the whole screen with a mix of normal and reverse text in several colors, just for simple stuff like completing an argument.
i've seen it, and it is indeed easy to tone the coloring down. The fish shell completion is amazing, I love it! Too bad the shell does not seem to support process substitution (at least not with the same syntax as bash or zsh), so I cannot use it for the moment.
This comes up every time Fish makes it to HN. It still bugs me too. So does up-arrow skipping the first matching history item and having to use right-arrow for the ghost entry that shows up. These two are 100% enough for me to change shells, and I will. Fingers crossed NuShell does well!
Can you describe what you like about NuShell? Never heard of it, but the Github page looks super interesting.
I struggle to imagine making use of it however. My normal flow just doesn't seem to need that power. I think I would benefit most from simplicity. Although, I could definitely see this benefiting from things being predictable, guessable, etc. Ie, when I rarely need more advanced features I'm less likely to need to look up documentation to figure out how to do something - as I often do.
Its line-editing and basic shell experience is not quite childproof yet (e.g. it can't parse tildes but only in Tmux), but I think it gets the balance right between being able to bash out a long pipeline quickly and having it work as you intended it. I have greatly enjoyed writing PowerShell in an IDE/VSCode, but not as a shell, but NuShell seems to capture the best bits in the line editor. I am most excited about the error reporting where it tells you about missing fields etc.
Not OP, but I find myself attempting to tab-complete Fish commands all the time. It's just how I've been conditioned by every other auto-completion interface I've ever used.
Ok, here goes a rant. It isn't difficult to accept the completion. I'm complaining about an unnecessarily complicated mental model that is easy to trip up on, and requires much more thought to use. When you use zsh-history-substring-search, you can press up-arrow and scroll through history filtered by whatever you have entered so far. That is the end of the feature description. With fish, you have barely started.
Up arrow scrolls back through history. With the enormous caveat that it doesn't show you the most recent one, which is usually the correct one; the list is physically split into head and tail by two different keys and two different UIs, so you can't just use it like a list, you have to remember what the top is so you can choose whether to read the ghost entry or to up-arrow and read that. If you know what the most recent one is, you shouldn't have to read anything to check, you should just be able to press the right sequence of buttons that does what you want to do. (I can never be certain that the ghost entry is actually the most recent one, because I've always thought it was frecency-based, probably because that's what similar-looking search tools (Google) have taught me. That's mostly my fault, but it's not something the UI was actually capable of teaching properly because without having to press up-arrow to see it, it is not linked to any particular list ordering; it is conceptually distinct and users are within reason not to see it as part of that list at all.)
Up-arrow works differently depending on whether you have entered text in the line or not; no text and it show you the most recent, add text and it won't. And perhaps worst of all, up-arrow actually does show the most recently typed command, but only if the matching sequence of characters was not at the start of the line. Actually that's inaccurate -- if a command matches in the middle, but also as a prefix, you can't just remember that it matched in the middle and blindly press up-arrow. That's ghost-only.
So there are in fact three different lists that up-arrow could be scrolling you through. Actual history (includes most recent); filtered history where last command did not have search term as a prefix (includes most recent); and filtered history where last command had search term as a prefix (does not include most recent). This is no longer a job for muscle memory. It's an active thinking exercise. So you have to remember the history stack yourself, including where in each line your search text will match, so you can stop and pause to think whether to press up or right at any given moment. I cannot think of another search UI that requires knowing where in a string your search term will appear, just for basic use.
Ultimately, dozens of times a day, I stop to think about which button to press, and am reminded of this spectacularly poor UI, for which apparently nobody was able to express these sentiments in the four years that the GitHub issue was open. I don't believe the behaviour can be configured.
Fish is great, and it brought about some great defaults such as autocompletion and autosuggestion. The only drawback is the incompatibility with bash.
The wonderful community made plugins that add these features to zsh (which IS compatible with bash), and it it's really great. My understanding is that there are still a couple fish features not implemented for zsh yet, but if you care about such things as bash compatibility then I'd suggest you give it a try instead.
> My understanding is that there are still a couple fish features not implemented for zsh yet
I'd love to know which ones! I was a bash user for 10 years, ZSH defaults put me off and it wasn't till I ran oh-my-zsh that I really learnt what I was missing, the following make me feel like a 10x-er ;) :
I've not used fish extensively so I couldn't tell you. My statement is mostly based on impressions from other people who have also tried both. I should give fish another go and see how I like it, but the bash incompatibility is a deal-breaker for it to become my daily driver.
I agree. The auto-features should be default for bash as well as it would really help some novices to get more fun out of the experience learning to use a shell and also as an experienced user I wouldn't want to miss this.
Because of that on every computer I have to work with for some time one of the first things is installing ZSH (and prezto).
I've been using fish as my default shell for a long time and recently started using it with https://starship.rs/, which adds some niceties to the prompt without having to go overboard with customizing and configuring your shell.
Can someone give a few prominent examples of fundamental differences from bash? I don't mean trivial things like having `config.fish` instead of `.bashrc`, or not using fi and esac to conclude if and case statements.
I noticed fish has:
* extensive syntax highlighting
* "global" variables shared by all instances of fish, persisting past reboots.
I've considered switching from bash to fish (something I never did with zsh). The main reason I didn't is Stockholm syndrome, or that I'm too used to bash by now.
I think you can get zsh to do most of what fish does out of the box. If bash is Ed, it feels zsh is emacs and fish is (neo)vim.
Zsh is huge and I always get a bit of a panic attack when someone has given me a ssh login with zsh as the default shell. And an irrational urge to maul a unicorn.
With fish, it feels more like a friend went and tidied up your apartment just to be nice.
I guess I'm so used to bash, that the limited support that comes from completions is enough - and I end up writing a bit of documentation and automation, and work on "foreign" (other people's) servers - and it helps me to work in a posix shell for that reason - with fewer surprises.
You might even find that fish does out of the box something bash (now) can too - just isn't enabled by default or in typical distribution's configs.
Ymmv - it's worth testing imnho. And more interesting than zsh, which just feels like someone was bored in it class in high school and added colors and tinkered with the prompt, and tried à million different ideas - but never really liked working in shell.
I was more thinking of how many(?) people will readily use a only slightly customized vim - and be reasonable productive in a standard config, vs emacs where the stronger trend seems to be building an ide on top of emacs - to the point were to users can't readily use each other's setup efficiently - or indeed use the standard distribution without customization.
Comes out of the box with a lot of useful auto completes, highlighting etc. Can do most of this with zsh and a lot of scripts/config but in fish it „just works“. Except you have to learn a new language. () for $(), „; and“ instead of „&&“ etc.
A big one is that unquoted variable expansion does not split on whitespace. This avoids all sorts of spaces-in-filenames bugs.
For a similar reason, command substitution only splits on newlines. Unfortunately, some commands like pkg-config assume that the shell splits on regular spaces so you will need to use workarounds like (pkg-config | string split "")
Good and well-thought shell language syntax (compared to ad-hoc hodgepodge of syntactic peculiarities of bash/zsh); reasonable defaults for the interactive shell. No other shell gives you this, for some reason.
That's not true. There are a few other shells out there that do. The issue is the popular shells tend to be the ones that go for POSIX (or Bash) compatibility and those that do go for a syntax redesign (for example) often get criticised for not being POSIX compatible. There is comment further down in this discussion describing those syntax differences as "bugs" rather than "features"; which just goes to demonstrate how ingrained Bash et al are to Linux/UNIX command line users.
Personally I see Fish and other non-POSIX shells like another programming language (arguably that's literally what they are). So switching from Bash to Fish - or whatever else - should be like switching from C++ to C#, Java, Rust, whatever. Sure there will be a lot of commonalities but it is the differences what makes the shift worthwhile.
That all said, I can't blame people for preferring a POSIX or Bash compatible shell because that's what you'd expect to find on any Linux or UNIX system. Or at the very least a Bourne Shell (sh). Plus most documentation online will be tailored for compliant shells. However it does become a self-fulling prophecy where compliant shells are more widely used because they're already more widely used. I'm fine with this though. People who want to make the shift and learn something new can still do so under the knowledge that they're breaking from the norms and all the potential complications that might bring; and people who just want something that's universal and works - irrespective of it's warts - can continue to do so.
Yes, you are right. I believe that we software engineers should not dwell in such conservative states of mind and innovate and even break from standards when necessary. Bash and POSIX were good enough 30 years ago when they first appeared. Now they feel really dated.
> The shell isn’t in charge of what data commands print out.
It could be if it captured stdout of processes it launches.
Of course, the program would have to output a structured format that the shell recognized to provide the shell the option to do what is described upthread, so legacy programs wouldn't fit in well with it unless the shell was programmed with how to extract structured data from their unstructured output.
True, but it's driven the method for output for a long time. If sh/bash exposed functions for objective output I'm sure a lot more utilities commonly in use would output in a similar methodology.
No it hasn’t. The shell isn’t involved at all in program output. When a program writes to stdout it’s talking directly to the kernel, and the shell is suspended and not running.
I don't really care what outputs the data I see. I care about how it's formatted and whether that format is easily readable + usable by consuming utilities.
I don't understand why your being standoffish over a technicality.
Okay, that’s fine. I think it would be nice for an OS to have a set of utilities that communicate with each other with objects instead of text. So I agree with you.
I’m just pointing out that this has literally zero whatsoever to do with the shell. You posted it as a comment in an article involving a choice of shells.
That's true for POSIX shells but if you're breaking POSIX comparability then you can start doing all kinds of clever/stupid hacks to turn pipes into something more than dumb byte streams.
Coincidentally, this is what I'm working on with my shell.
Shells are just user interfaces so they don't have to have pipes nor even be CLI based. For example on Windows, explorer.exe is technically a shell. On Linux you can run git as a shell. Obviously these don't solve the problems you guys are raising for optimum command line usage but it illustrates that interesting things can be done if you shift your mindset from POSIX. For example some REPL environments might make a higher level language it's first class citizen (eg Powershell).
The standard byte streams are just 3 file descriptors and on Linux are generally symlinks inside /proc but all that is handled by the pipe syscall (as you stated). However there is still a lot of code between the shell parsing your entered command line and pipe() being called and how the shell decides to implement fork() and pipe() is largely down to the shell designers. Going back to my earlier point about POSIX shells, there is a general expectation that these kinds of shells should just fork() and pipe(); which makes sense when you think about their heritage but it does allow developers to get creative if you're intending to break POSIX.
For example they could check the receiver processes for a signature (magic byte or something) to see if it's a supporting tool and if it is, the shell could then "man in the middle" the pipe; where it sets itself as the destination pipe for the first process and the source for the second process (eg `ls | grep foo` would be called as `ls | shell | grep`). That way the shell could then wrap STDOUT from `ls` up inside a more complex object and pass that to `grep`...and only do all this if `grep` already appears to support this new shell's object system.
Other ideas is that type information could be passed via a fourth file descriptor, UNIX socket or over a localhost TCP/IP listener. Or maybe you don't support smart processes and instead write your shell to do some of the heavy lifting instead via shell builtins (like how Bash has a few builtin functions) where you could write smarter data wrangling tools so it doesn't matter what crap `ls` or `grep` throw at you because you can pipeline that into a shell builtin.
This last approach of smarter builtins is the direction I took with my own hobby shell but I'm now looking for ways to pass that data type information along to other processes without breaking non-supporting processes.
I'm half asleep at the moment so probably haven't don't a good job explaining my thought process but there are a few of use playing around writing "alternative shells" (for want a better description).
As much as possible, syntax looks like shell commands, and blocks uniformly end with `end`. You don't get the messy inconsistency of sh where functions use braces and conditionals use ALGOL-style `fi` and `esac` and loops use `done`. Beyond that, some control structures even support flags: if you want to read up on function definition you can run `function --help`, and if you want to define a function `foo` that completes like `git` you define it with `function foo --wraps=git; ...; end`. That means you have to keep less in your head.
A lot of things are even defined as ordinary fish functions. In sh, aliases are a dark and evil feature that hooks into the parser and can be used to create rudimentary macros. They have some really surprising behavior. But in fish, `alias` is a shell function and you can get the complete source code on your screen by running `type alias`. It doesn't do any evil things because it can only do things you could do yourself.
Fish has sensible variables and arrays. All variables can be arrays. When unquoted, variables expand like "$@" in sh, so packing multiple arguments inside a variable is trivial and there's no need to worry about whitespace. Command output splits on newlines, which means that things like `for file in (find . -iname 'foo')` just work, assuming you don't have newlines in your filenames.
Writing one-liners in fish makes me much less anxious then doing so in sh.
For me the killer feature is that for me, as a casual user, it's easier to be productive. There are just so many weird little things that folks do in shells that I don't do often enough for me to remember exactly how to do them.
Though I'll say up front, again as a casual user, I'm not sure exactly how fish accomplishes making me more productive than bash. I'm also don't know if I ought to switch to something like zsh. I often read folks saying great things about zsh but it seems more like something aimed at "power users" and that ain't me.
oh-my-zsh has 'sane' defaults (and by that I mean 4-8 hours of configuration at least). I'm in the process of moving from that to self-managed zsh and I'm surprised with the stuff that doesn't come default with ZSH, such as not setting the <title> of the shell to $(pwd) or the currently executing process, or control codes.
I love the way it predicts what I will write, how attractively it presents the predictions, and how it understands commands and completions based on man pages.
But with decades of bash experience, I struggle with making even the slightest scripting in fish's own language for whenever I want to make a smart little addition to my environment.
This might make me a bit of a freak, but the one thing keeping me from trying out Fish for real is decent vim bindings. I know Fish has vim bindings, but I found the feature support pretty lackluster and the behavior of some keys like 'e' to be inaccurate.
I know some folks say that vim-style editing is overkill for a shell where you're often just submitting one-liners, but it saves so much time for me to be able to just jump right into the middle of a previous command and change one word without holding down arrow keys to get there.
Granted, it's been awhile since I looked into Fish's vim mode, so maybe it's improved. Last time I checked, it sounded like it just wasn't a priority, since Fish's selling point is the intelligent autocomplete and such.
If you are working on a complex, long command pipeline, in bash you can use Ctrl-x Ctrl-e to open your $EDITOR to edit the line as needed. The commands will be executed as soon as you save the file and exit.
Yes, the only shell I actually enjoy writing scripts with. Bash is old and ad-hoc, and zsh is basically bash on steroids. Fish is something where actual language designers have sit and thought thoroughly how the shell language should work and look like.
Something not discussed enough is the competing concepts of shell as hyper customizable UI where fish wins, and shell as a light programming language for short casual scripting, where I kinda have to use standard uncustomized bog standard identical everywhere bash.
Is it really a “bug” if you’re writing incompatible code for Fish? Bug implies unexpected behaviour but I’d argue that Fish’s non-POSIX behaviour is well discussed, documented, and thus should be completely expected.
Yes and no. One nice thing about shell, is that you can log your commands/look at your history - and easily automate tasks (turn an interactive session into a script).
The only trouble is, such snippets have a way of sneaking into documentation, ci pipelines and other places.
And then non-posix isn't quite as nice anymore. Even if csh or fish might be the nicer language.
I do think the oil shell project is on the right track, by trying to "fix" shell (and fish is a great source of inspiration for the interactive part).
Still, when plan9 didn't manage to take over, I guess I'm a bit sceptical about any new shell having much success...
I use it as my daily driver and I've also started writing some smallish scripts in it. It's actually fun whereas bash always seemed rather tedious. I love how easy it is to parse arguments with `argparse` and to add completions through `complete`.
Also fish utils like `string join` etc. are super helpful when writing small scripts.
Thought they were being ironic with the 90s / Netscape / glorious VGA comments but maybe these really haven't been updated in an age. They've got screenshots not updated since 2006 (based on the release date in GitHub for release 1.21, given version 1.21 is show in one of the screenshots! You can also tell they're older from the chrome on the Mac terminal title bars)
I think they're just being honest. All of the features they boast were completely possible in the 90s. The only reason we didn't get them in the 90s was people not realizing they were so possible, or perhaps not wanting to leave their 70s style behind. A great deal of computing, especially on the *nixy side of things, is stuck in the past. Stepping back and looking at what you're used to and saying 'but how would it work if we were designing it from scratch today with all the hardware and knowledge we have now' doesn't often come up. And it's often seen as an attack on the older way of doing things for no good reason.
I love Fish. I'm likely not their target audience.
I've been using it for years. Since the early days in 1.x land for sure. The homepage has never changed and I still laugh at the tagline. I find it's auto-completion, history and niceties indispensable. I'm the person who asks you what the command is to rerun the tests. With Fish I never have to ask you again. I just remember part of it, and suddenly I've got it.
I find its scripting language much simpler to follow than bash. I don't have a lot of scripts, but the ones I do are easy to manage. The only hiccup I get into is when I have to look up something on stack exchange, and of course the example is in Bash. These days though, with Bass and fisherman and so many other tools, i have options.
Years ago I would explain to other code friendly designers, I'm weird, don't use this stuff. Go grab zsh. Lately though it's gotten very friendly. Really the only downside for a light scripter like myself is that need to convert bash examples to fish problem. Beyond that I feel it's actually a much nicer shell for new to terminal folks.
Anyways, just an anecdote to add to the pile. Thank you to the devs that have supported it over the years.