I use Zsh, it's such a tremendous improvement over Bash. Not only does it handle parameter expansion much better than any Unix-style shell, but it also has a lot more useful built-ins that can save you from having to call out to external programs to do basic tasks, like getting the absolute path of the directory that contains the current script.
It is so unbelievably feature-rich that it's almost impossible to describe all of its features and merits, but you can safely ignore most of them and the basic day-to-day experience will just be "Bash, but better".
No program is perfect, but Zsh I think is pretty damn close. That's not because it doesn't have flaws (it definitely has flaws), it's because it does such a good job at doing what it does, that all its flaws seem minor and none of them fundamentally get in the way of it doing that job.
One additional thing I'll say is: it is probably the only Unix-style shell where I would feel comfortable writing 1000+-line applications with a CLI, tests, etc. I would never do such a thing with Bash or some minimal Posix-compatible shell. It's a very sensible system scripting language, alongside Python, Perl, etc.
It may be better bash, but it's just an incremental improvement, no more. It still follows the same philosophy as bash.
On the other hand, fish shell feels like a bash rethought and optimized for interactive use. It's now my daily driver on all of my Linux and Windows machines (msys2 port). After using it only for interactive sessions, I also started to write my utilities in fish, which is a breath of fresh air compared to both bash and zsh.
The only place where I still use bash is when I need to write a script that needs to be shared with others, everything else is now fish.
Within 30 seconds of installing fish, I shouted, "How the hell do I disable these annoying suggestions?! This is worse than Clippy!" So I searched fish's docs and learned that it wasn't possible to disable the suggestions! The fish docs state, "Configurability is the root of all evil"[1]. As an Emacs user, this was the most offensive thing I've ever read, which is saying a lot because I once read a work of erotic Star Trek fan fiction about a love triangle involving Dr. Crusher, Wesley and Worf.
I have to admit, I’m not surprised the fish user would footnote with (an unclosed) ¹ on HN. :) As for me, I prefer the predictability of [1] and /bin/bash.
I use fish as my default user interactive shell but I still agree with you. I despise this philosophy of "configurability is the root of all evil" coming from fish and "every preference has a cost" coming from GNOME.
I think these projects are extremely opinionated and they will inevitably drive a lot of users away. Both fish and GNOME strive to provide "good" defaults out of the box but those defaults will never appeal to everyone. I ended up liking fish but I still despise GNOME and everything related to it.
Likewise, I don't use fish for exactly this reason. It seems extremely fine tuned to meet exactly the preferences of its developers, and eschews all further configurability. The Clippy comparison is brilliant, by the way, pretty much summarizes my exact feelings about the suggestions.
I ended up back on zsh. It's a real shame, because fish adds quite a lot in terms of improved subshell syntax and intelligent string manipulation.
Seems like someone should have been able to disable the suggestions using a plugin or something, given that IIRC fish has a plugin interface. But as far as I can tell no such thing exists.
The advantage of that, though, is that you can still benefit from the many "how do I do X in bash" posts on various fora, Stack Exchange, etc. With the more esoteric shells you have a much smaller community.
I prefer to keep my utilities scripting and interactive shell the same. That way I don't have to keep two sets of gotchas in my head, and don't accidentally use the wrong syntax in one place or the other sometimes leading to confusing misbehaviours.
While I don't mix bash/zsh/sh/... I will consider python/node/other if I need specific things that they do well or I'm making something more than a simple tool or automation (for which bash is either underkill or just thoroughly unsuited). They are sufficiently different that I'm not going to cause myself the sort of mix-up I might with flipping between shell scripting syntaxes.
The really cool thing about shell scripts is that they are just a saved version of your interactions with the ability to edit and refine later. If you stop using the shell interactively you've just lost the main advantage of using it for scripting.
That's a very good point. I have stuck with it because I am comfortable with it, but I have been wanting to spend some quality time with these alternative shells for a while. Have you tried Elvish? I am particularly curious about that one, because it seems like the primary Fish "competitor", but seems comparatively a lot less popular.
I also use fish on basically every linux machine, desktop or server, but I've also tried elvish for a bit. My shell scripts are still mostly bash or even POSIX though, because I haven't rewritten them yet, or they're setup scripts that should work right after the install without installing an additional shell first.
I'll admit that I haven't really dug into scripting with elvish, because I quickly abandoned it again.
My main reason for leaving elvish again was the good syntax completion in fish. Yes, you can create your own completions in elvish and they'll probably be just as good, but that takes time and I ultimately decided not to bother with it.
> it's just an incremental improvement, no more. It still follows the same philosophy as bash.
It is actually the other way round, with bash being an incremental improvement over zsh. Starting from v3, bash has adopted many features that zsh had had for a long time.
Both, bash and zsh, are incremental improvements over the Korn shell.
> It's a very sensible system scripting language, alongside Python, Perl, etc.
I’ve always assumed that the main benefit of bash scripts is that they’re portable and universal. If you’re willing to compromise that, why not just go with python? I don’t really understand which gap zsh fills here.
I can't speak for anyone else, but for me, it's because Python is cumbersome for doing the sorts of things that are easy in a shell. You want to capture the output of a command, parse it as a tab-separated table, extract the 3rd and 4th columns, and then use them to create new users with the values supplying usernames and passwords. Can you do that easily in Python?
For all its syntactic sugar, dealing with files in python (which comprises probably 90% of what I open a shell for) still requires a fair amount of boilerplate. Which is good for a general scripting language, but makes it poor for the the kind of tasks I expect of a shell.
I'm not arguing for Python over bash, I'm asking about the value of zsh as opposed to bash or python. So why couldn't one do what you describe in bash? The answer probably is you very well could. So why use zsh for scripting?
I've generally ported _to_ Python to see improved portability: the problem with bash is that it's not just what versions of bash you have installed (if you support RHEL, MacOS, etc. that can limit you significantly) but also all of the utilities which you call so you probably end up needing to wrap things like readlink once you need to run on more than one of GNU, BSD, busybox, etc.
Obviously you can get a fair amount done with pure POSIX but for me it's almost inevitably hit the point where you rewrite it in something else and realize that it's like 30% fewer lines of easier to understand code.
If you choose vim keybindings for navigation, it utterly breaks reverse-r search and the hacks you have to use to fix it do not make it an equivalent experience.
It's like the zsh folks said, "fuck those vim guys".
If I didn't have to use a Mac at work and our tooling didn't behave oddly in bash, I wouldn't use it. Bash is much more comfortable.
I'd say that if you want vim-like bindings, zsh is a much better option. It provides Vim's text objects, surround.vim bindings, and visual selection which bash does not. Also unlike bash, you're free to create your own keybinding if none of the builtin ones suffice. I did exactly that to get an increment/decrement operator that behaves exactly like Vim's ^a/^x.
It's like the zsh folks said, "I like those vim guys".
As a vim user, zsh's vim mode is far better. You do need a few lines of config for stuff like allowing deleting back past the insert position. However, I have never found it lacking, unlike bash which sometimes lacks some motion I try to use.
I didn't mean to imply that Zsh was somehow more portable than Python. And I agree with the sibling commenter that Python is probably more portable than Bash.
I use Zsh for many of my personal scripts, but at work I would never even try to get it into one of our production containers.
I am very aligned with what you said but when it comes to shipping shell scripts (say sysops stuff, init, cron, ..) I tend to stick with the ksh/bash ecosystem mainly due to more tooling (shellcheck, shfmt, bats/bash_unit).
Most things that works in bash obviously works fine in zsh, but as the article very eloquently points out - lots of gotchas.
I hear this argument from zsh purists all the time, I'm pretty sure it's made up. I've used oh-my-zsh for years with several plugins and the startup time is basically imperceptible. Maybe it's slow if you're running on raspberry pi or something.
Yeah, I can't quite comprehend what makes the terminal experience on MacOS feel so sluggish. At first I thought I was being spoiled by Alacritty, but even Konsole feels more responsive than iTerm these days.
Doesn't take long to track down the culprits. nvm is a huge contributor to startup lag, IME. I am not a frontend dev, and rarely have to touch Node, so I comment out anything nvm-related for daily work.
I agree nvm is suboptimal. I've been doing web-related things for a living since 1998 and I care about tooling. YMMV but I have a strong preference for managing node versions via `n` (installed via tiny util `n-install`).
It is easy to go overboard with oh my zsh for sure, but startup time, as long as it's less than ~5 seconds, is not likely to be a big problem for most people. On slower machines the real killer is the time it takes for the next prompt to appear after each command. There are mitigations, but I've definitely had machines where it is almost unbearable.
Five seconds really is unusably slow, in my opinion. Even a tenth of that is grating. If I want to run a one-off command, I open a new terminal to do so, and close it when I’m done.
My pretty extensively customized zsh config with ohmyzsh takes maybe a quarter of a second to load... Maybe I don't have as customized config as I thought because if it is taking a second or more I can't imagine what is being loaded.
Or zgenom[0]. Or if you want to get ESPECIALLY froggy and async with your shell startup, zinit[1]. I ran zinit for years before moving to zgenom. A large swath of electron apps use some weird NPM library to “resolve” your shell environment by kicking up a full interactive shell and then reading the environment variables out of it. zinit messed with that and would hang a lot because of all it’s async loading.
Would love to be able to transpile zsh or any other higher level scripting language into Bash for portability reasons alone. Is there something that converts bash, sh, or zsh into an AST?
Also useful would be a tool that tells me if I'm using a zsh construct that isn't supported in bash... or even better, how to do it in bash
Not really what you're asking for, but a language that compiles to bash for portability reminded me of Batsh [0], a C-like language that compiles to bash for Linux/Mac and batch for Windows.
It is so unbelievably feature-rich that it's almost impossible to describe all of its features and merits, but you can safely ignore most of them and the basic day-to-day experience will just be "Bash, but better".
No program is perfect, but Zsh I think is pretty damn close. That's not because it doesn't have flaws (it definitely has flaws), it's because it does such a good job at doing what it does, that all its flaws seem minor and none of them fundamentally get in the way of it doing that job.
One additional thing I'll say is: it is probably the only Unix-style shell where I would feel comfortable writing 1000+-line applications with a CLI, tests, etc. I would never do such a thing with Bash or some minimal Posix-compatible shell. It's a very sensible system scripting language, alongside Python, Perl, etc.