Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active December 14, 2021 20:30
Show Gist options
  • Save JoshCheek/02fc5cab78ffa0c7cc95 to your computer and use it in GitHub Desktop.
Save JoshCheek/02fc5cab78ffa0c7cc95 to your computer and use it in GitHub Desktop.
Why I Chose Fish Over Bash For Students

Why I chose Fish over Bash for students

I'm currently the lead instructor at Code Platoon and an instructor/developer at the Turing School of Software and Design.

I've been advocating the Fish shell and when the choice is up to me, I choose that for my students. Enough people ask about the decision, particularly in relation to the preinstalled Bash shell, that I figured it's worth laying out my reasoning.

TL;DR

Fish addresses many of bash's shortcomings and is much kinder to newcomers, with only 3 or 4 new things to learn for people coming from Bash.

The decision give students my defaults

I used to let students choose whatever shell/editor/etc they wanted. But most students are not in a position to understand the tradeoffs, and they fear making changes. This would often lead to situations where students would defer all choices and 6 months into the program wouldn't have so much as a coloured prompt. Why does a coloured prompt matter? It means that every command they type, they have to scrutinize carefully to see what the command was and what the output was. Add that to all the other costs of being new, and it gets expensive quickly!

The problem with being a beginner is that you get a lot of practice in staying a beginner. What a beginning tennis player does most of the time is chase the ball. They get to be really good at chasing the ball, but all other forms of tennis involve hitting the ball.

-- Tim Gallwey

I eventually decided that letting them choose had little value because it meant inconsistent environments, most in some state of brokeness. Students were mostly overwhelmed by all the decisions they had to make, and were too ill-informed to understand the tradeoffs anyway. It turns out that overchoice leads to dissatisfaction, regret, and paralysis. I know the tradeoffs, and what they struggle with, so I'll make those choices for them.

So then, the question becomes "what environment should I give them?" I've tried 4 different editors now (Sublime, Atom, RubyMine, and Vim), and two different shells (bash, fish). In the end, I realized that most of the decisions I make for myself are better than the defaults, and due to my prioritization of feedback, my choices are generally good for learners. One of those decisions was the Fish shell, and this post is intended to explain why it is a better default than the Bash shell.

The case for Bash

Based on conversations I've had, there are 3 arguments for Bash:

  1. It is already installed.
  2. Most shell code is written for Bash.
  3. Most people that can help know Bash.

My perspective: We are installing many new things already, and don't accept this as an argument that we should stick with many other defaults. Fish is mostly compatible with Bash. And there are only a small number of new things someone with Bash knowledge needs to learn in order to use Fish.

The case for Fish

Highlighting

Fish will highlight the command they are typing differently from the arguments they are giving, making it apparent that this first bit of text is different. If it is not made explicit like this, students can go months before they understand that the first thing they type is a program and the things after it are arguments.

highlighting args

If they type an incorrect command, it highlights this in red, so they immediately know, as opposed to knowing when they get an error message after running the completed command.

highlights incorrect commands

It highlights quoted args differently to let you know they are a single argument, and if you have incorrect syntax, it highlights this in red:

highlighting identifies command vs arg vs quoted arg vs incorrect quoting

Suggestions

Fish will suggest previously typed commands. What was that command to start postgresql? type pg and it will suggest whatever I put last time! This is even directory aware, so that suggestions will be be prioritized based on where I use them!

suggestions

It understands program options and lets you tab complete to see what the option is and a brief description of the option:

suggests option completion with summary

Highly compatible with bash

Syntax for common use cases is usually the same:

Wildcards are the same

wildcards are the same

Redirects are the same

redirects are the same

Pipes are the same

pipes are the same

Things Fish does much better than Bash

It correctly handles string escaping where bash completely falls down (Bash later added $'this kind of string' to compensate).

fish quotes correctly bash does not

It's much easier to set up a prompt that changes based on the success of the previous command (bash can do this, too, it just took me several years to figure out the right way to do it -- the PROMPT_COMMAND variable, if you're curious)

success displays in the prompt

When you get to scripting it, the language syntax is dramatically more understandable. I tried to write a function just now, in bash it took me 2 tries, then I wrote it long-hand so I could press up to see how it translates to one line (5 tries in the recording because I messed up). Notice that even if the fish version wasn't obvious, the autosuggestion from my previous success would let me know. And while defining it, I get syntax highlighting and proper indentation.

functions in bash vs fish

Fish handles string escaping and allows you to edit across lines. I'm not sure what library bash uses, but watch what happens when I try to go up to edit what I wrote (also notice I got the name wrong at first, but fish highlighted it in red, so I knew to go fix it). It's good enough that I've written 30 line programs inside of strings in the shell!

editing in bash vs fish

Bash only recently got basic data structures like hashes and arrays, and the syntax to use them is both unintuitive, and forgiving of mistakes (meaning it is easy to do the wrong thing, and difficult to realize it). Here's an example: setting arrays involves complex syntax, whereas in fish, it's the same syntax you use for everything else (a command followed by args) and look how many ways there are to access it wrong in bash, many of which you wouldn't realize you got wrong unless you knew to check it against an element with a space. And you have to opt into safe behaviour by quoting everything... I'm not even sure what the unquoted use case is!

arrays in bash vs fish

And here's bash's syntax for hashes: http://stackoverflow.com/questions/1494178/how-to-define-hash-tables-in-bash

Another thing about Bash

Also, the relationship between .bashrc, .bash_profile, and .profile is utterly confusing and leads to bugs when things get placed in the wrong file (I'm pretty sure this is because it's inconsistent across operating systems). A very competent friend (maintainer of gems we all use, who prides himself in knowing everything) once confidently told me what they all did, and I tried it in front of them and it was incorrect.

Summary

So, Fish addresses many of bash's shortcomings and is much kinder to newcomers, with only 3 or 4 new things to learn for people coming from bash. I documented most differences I could think of over here, and that document goes much further than even I actually need. In our material on the shell, there's only one place we need to differentiate it from bash, which is in how environment variables get set (1, 2). So the cost is low and the value is high.

Salutation

Hope that explains my motivations sufficiently :)

@ktgvv
Copy link

ktgvv commented May 23, 2019

Hi.

I came upon this gist from searching more about FISH next to BASH. You're spotlighting quite the obvious truth beyond just comparing both. This is interesting in that you too are a power user who keeps a beginner's eye. Some dinosaurs may dislike that, but it's the unvarnished truth: as they still are, BASH and ZSH belong to history. The only reasons to still use BASH are that:

  • BASH is both updated to keep up with its time and close to ancient shells,
  • BASH is widespread,
  • BASH is preinstalled and set by default most of the time, partly for of the former two, and
  • BASH gets more and more flexible.

When I first got my hands on a UNIX shell, in late 2011 or early 2012, I was fifteen or sixteen, and all I knew to do in computer science was markup languages and using text editors. Before then, the only command-line interface I had clumsily used was CMD. Back in the days, I just got my first Mac, and soon, I was looking for fine tweaking. This lead me among other things to enter prewritten defaults write commands in the terminal emulator, only understanding that some words meant some things and had to be entered in a given order. I didn't know the concepts of variables, data types and stuff.
    In late 2014, I started learning computer science the hard way in 42's admission trial month. We were sit in front of iMac with but a bugged Finder, iTerm2 with ZSH, a libless ANSI C and Chrome, which was all we had to complete the daily projects. Today, I know this was still way more that what we needed to succeed. But back then, when you get thrown in front of black screen with white text, while having to write code in a language you know jackshit about, with documents you understand a word on two from, it felt like being a living failure --- most quit in violent rage outbursts or total mental breakdown, sometimes just hours away from the end of the month. Those of us who survived went deeper into the white rabbit's hole, and today, we seldom use Finder for things even the 1977 SH does better. I kept using ZSH. Like many beginners, I've been through the trend to use Oh My ZSH just because, from which I quickly came back, because I realized it was pointless; the vanilla ZSH did more than what I needed, and overall, more than what I was able to do right. I truly started to dive into ZSH in mid 2015. Soon, I understood that all I did was using BASH through ZSH since the beginning, even at 42. Today's BASH and ZSH are mostly the same, or at least, can be made almost the same. Yet I kept using it, increasingly knowing how it works, in which runcom had to go what setting etc. Eventually, I finely understood this mess, and as ensuring that all my scripts were BASH scripts in the first place, I definitively reverted to BASH in early 2018.
    As of today, finally able to write BASH scripts, I feel like I can legitimately say a word. All in all, it took me four years to partly master BASH. And trust me, I'm the kind to RTFM. These phat paragraphs are my example of how confusing BASH -- and SH and ZSH along -- is.

Both BASH and ZSH may be loaded with features, it doesn't change the fact that it's a newcomer's wasteland. Their man pages have clearly been written by computer scientists; Simple Wikipedia-like versions would be welcome. And that still wouldn't help about the base unfriendliness of those. [Well, it could've been worse. Look at man git.] They could implement multidimensional arrays or such big feat into BASH, if it's badly accessible or undocumented, few people would use it, fewer would use it right.
    It's good that BASH has that many features and such a userbase, but contemporary basics wouldn't be luxury in 2019 -- after Jesus Christ was born, not before. BASH lacks modern string handling --- and I'm not even talking about PowerShell-style character handling. BASH lacks syntax highlighting, due to readline. BASH lacks a simple mode in which fewer runcoms are used with a better differentiation. Unfortunately, as so many of the classic powerhouses, BASH falls short to be used just like nerds' inside jokes fall flat; something that only a core of people understand amongst themselves which outta be otherwise great.
    Had I known about FISH earlier, I would've dumped ZSH, and I'd have bothered with BASH only for BASH script to have wide-reaching scripts. Only elitist fossils full of bad faith advocate the use of BASH or ZSH against all odds. Truth be told, there's plenty o' room for improvement.

Nice read.

@JoshCheek
Copy link
Author

Well, it could've been worse. Look at man git

😂

fewer would use it right

I frequently encounter bash scripts that are broken or will be broken if given the right input (usually because of quoting)

Nice read

Ty ^_^ Hope your fish excursion is going well. I've been happily using fish for nearly 7 years now. IMO, it's got 3 killer features:

  • Autosuggest is a paradise
  • Quoting is done correctly (bash is outright sinful here)
  • Multiline editing is the better than anything else I've ever seen

It does have a few drawbacks, too, these are the ones I can think of offhand:

  • There is (maybe was, not sure if they addressed it) a bug where jobs could get zombified depending on how you wired up stdin
  • Tab completion could block the shell if the completion needed to execute a program that was slow (also may be fixed now)
  • It's not POSIX compliant, which can lead to other programs breaking if you set it into the SHELL env var (greatly alleviated now that they added && and || operators)

Anyway, yeah, I'm still a huge fan ^_^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment