Hacker News new | past | comments | ask | show | jobs | submit login

It is worth, as a long time Bash user, to change to ZSH?



Perhaps it's niche, but there's a single feature that makes me use zsh over bash: EXTENDED_GLOB, used together with * filename expansion.

    ls **/*.d
gives me all files, recursively, that end in .d. That's available in bash too if you `shopt -s starglob`.

But it also gives all directories, so if I do eg

    grep pattern **/*.d
then I get lots of error messages about trying to grep on directories (if I happen to have directories ending in .d). With zsh, I can do

    grep pattern **/*.d(.)
and it will restrict to just files. I use this pretty often, and it saves me from many `find | xargs` commands. I pretty much only use `find` when there are too many matches for a single command.

My muscle memory types

    fgrep -l SOMESTRING **/*(.)
multiple times per day. That'll list out all files containing the literal SOMESTRING anywhere in or below my current directory. I'm sure I could be using one of the fancy grep replacements, and I have in the past, but this works Good Enough and only requires zsh to be installed, so it's what I have held onto.


At least GNU grep has `grep -r --include='*.d' <pattern>`


I switched to ZSH and was quite happy with it, now using FISH - mainly because of it's excellent auto-completion that displays as you type. Otherwise both ZSH and FISH are good options IMHO.

Although for typical "shell-scripting" I still use BASH for the most-part where scripting languages like Python aren't as suitable, so my scripts can be used on other peoples systems.


Do you have some personal examples where Python wasn't suitable over bash for a non-trivial task?

I am admittedly a not very good bash'er, and this week at work I whipped up my first "complicated" bash script, but ended up rewriting it in Python. It might have just been the case that the IO bound nature of my task fell right into Python's strong suits (async IO), but it had me wondering what scenarios a bash script would be better.

Essentially I had to:

* iterate over a list of hundreds of thousands of files

* make an api call via aws cli

* take result and process it through a few shell utilities (`date` and `touch`) to then update the timestamps on the files.

I initially wrote it in bash which spawned ~16 background workers (threads/processes?) via `&` and blocking via `wait -n`. This "worked" but was pretty slow as the threads were thrashing checking for responses. Doing anything more than 16 caused my computer to crawl lol.

I then rewrote it in Python with async IO and the async subprocess API (to run shell commands) and it was an order of magnitude faster.

I wish I was better at bash, but maybe I just haven't spent enough time with it. Doing this task made me feel like I could pretty much doing most things in Python if I need a non-trivial script.


I think it's less about pure suitability, and more about availability.

If I write a Bash script, I can be reasonably certain it will run on any unixoid system that came out in the last years. With Python, I am now in version hell (it's ridiculous how many Python2-first-servers I still find), I'll run the risk of includes suddenly becoming incompatible or buggy.

Can Bash do everything that Python can? Almost certainly not. But it is available, it is relatively simple (and almost minimalistic), and it forces you to learn more about standard unix tools.

Your specific use case ... well, I think that's pretty unusual - I'd wager if you had avoided the parallel processing and done it in a more linear way, you've had a better time.


That makes sense! I will admit it was a bit of fun clobbering together the bash version at first. It reminded me of starting out programming where everything felt a bit esoteric lol.

> if you had avoided the parallel processing and done it in a more linear way, you've had a better time.

I had to process ~500,000 files, and the aws api call was on average ~1 second, so it would have been a significantly longer time to process linearly. For example the bash version I whipped up processed ~30k files in 2.5 hours, while the python version did 30k files in ~20 minutes.

But yes I agree, if I didn't have to do such a large volume at once the bash version would have been just fine.


> If I write a Bash script, I can be reasonably certain it will run on any unixoid system that came out in the last years.

Except for, like, all the (free) BSDs and Illumos. What “unixoid” systems were you referring to, exactly, other than Linux?


Other than bash not being portable to even the exact same machine, due to having so many footguns. Creating a new file can potentially fail a previously working bash, because it may have used .txt expecting a single file, or whatever, and there are a million others.

Don’t get me wrong, I accept that there are legitimate use cases for bash, but I really can’t help but feel that anything longer than 3 lines (including #!) is better off in anything*.


This description, to me, sounds like you wrote a Python program... in shell. Nothing wrong with Python programs, but writing them in shell is about as pleasant as writing them in C.

The shell’s parallel processing capabilities shine when you want consecutive stream transformation steps to run in parallel (note that you can pipe to and from loops, over multiple descriptors if necessary). When your task can be structured like that, it will often take as much time to write a parallel implementation in shell as it will a serial one in Python (etc.). On the other hand, running multiple iterations of the same step in parallel is, as you’ve seen, awkward.

If the only thing you actually need to parallelize is HTTP requests, you might find piping things into aria2c[1] or the like to generate temporary files with responses and then processing those serially (best if your tool can tell you on stdout when a job is done, otherwise inotifywait and its ilk[2] may help if you’re uncomfortable just hammering the filesystem). When that is not enough, you could try GNU Parallel[3] or, if all else fails, implementing a jobserver in the style of GNU Make[4], which you may find more pleasant to do in shell than your current design. Generating a Makefile and then letting Make manage the worker pool (and call out to a separate shell script for each job) is also a possibility.

But at that point (in particular if you’re not I/O-bound) it might be best to just not do it in shell[5].

[1] https://aria2.github.io/manual/en/html/aria2c.html

[2] https://jvns.ca/blog/2020/06/28/entr/

[3] https://www.gnu.org/software/parallel/

[4] https://www.gnu.org/software/make/manual/html_node/POSIX-Job...

[5] https://sanctum.geek.nz/etc/emperor-sh-and-the-traveller.txt


Python isn't suitable (by default) when the main task is to run multiple other programs, in pipes and elsewhere. Env vars are a bit harder to get to, etc. Common sys-admin use cases basically.

Yes, you can write a run() function that handles everything, and there are some 90% solutions in subprocess now, but the defaults are not as simple as a modern shell on this dimension.

Of course, if you need to do any string manipulation, advanced conditionals, or math, Python quickly pulls ahead.


Ditto. Had been using zsh for ~5 years as a better bash, but around 6 months ago tried some of the plugins for suggestions and history, but ended up switching to fish.


> FISH - mainly because of it's excellent auto-completion that displays as you type.

Said functionality for zsh:

* https://github.com/zsh-users/zsh-autosuggestions


In fish it’s built in, that’s the beauty.


I switched to fish and loved it. Then I realized there was no way to make the completion and matches case sensitive or non-fuzzy. On their github they say something like this would require the c word ("configuration") and they won't do it.

So I moved to zsh, enabled two plugins and borrowed a config. I have 99 percent of what I like about fish. It's quite awesome.

If anyone is looking to try out zsh, please please please don't start with oh-my-zsh. I actually went zsh-fish-zsh. My first zsh attempt being with oh-my-zsh.


I started with oh-my-zsh when i moved to mac for work. What am i missing?


Tab completion alone is a good reason to switch. bash completes only filenames most of the time even with a bunch of third party completion scripts. Meanwhile, zsh provides smarter completion as part of its default installation, which you can enable with this 3 line configuration:

    autoload -Uz compinit; compinit
    setopt menu_complete
    zstyle ':completion:*' menu select


I switched from Bash to ZSH with the caveat that I use prezto and powerlevel10k (included with prezto) and I will never go back.

I had to turn off some of the Zsh-specific brackets and quoting features to make it more bash-like because of the tools I use which make it kinda wonky to use with Zsh but otherwise it’s been absolutely fantastic. Remoting into our systems that only have bash feels absolutely prehistoric.

https://github.com/sorin-ionescu/prezto


> It is worth, as a long time Bash user, to change to ZSH?

It doesn't make a lot of a difference. For me the major selling point of zsh is that it has two forms of process subsitution: regular <(...) as in bash, based on sockets, and =(...), which creates temporary files. This allows you to do some neat things that are not possible or comfortable in bash.


If you like vim mode, the zle vim mode is more complete than readline's, it can handle test objects for example. That's a small thing but that's nice. Prompt config is also quicker/easier to remember. Small things do add up.


bash is great for scripting and zsh can be made great for interactivity. I use zsh with prezto and history-substring on and auto-suggestions on, it's great.


Probably not. I think they both have comparable features, and by default are pretty bare bones without a lot of extensions and configuration. If you do want to try something new I would suggest fish shell. It is like a fully tricked out bash or zsh, but out of box. It is also very fast, because those tricks are built directly into the shell. I used to use zsh and after adding all the bells and whistles it got very slow.


I recommend Fish. Very nice shell.

https://fishshell.com/


I see no reason to continue using Zsh or Bash in a world where Fish shell exists.


There are at least two, though they may not be relevant for everyone: POSIX compatibility and ubiquity on random systems where your ability to install things is limited.


Some things won't work out of the box if your shell isn't posix compliant. For example, I once installed Ocaml, and its installer assumed my shell was posix, so some of the commands broke (I forgot the exact details now). Also NVM (node version manager) doesn't work with fish (or at least at the time).

Sometimes there are alternatives or workarounds, but the fact is that using fish does come with that downside. Doesn't come up often, but it is annoying when it does come up.

I like fish btw, just saying that I disagree with your "no reason to continue using zsh" comment. I use zsh because I was fed up with random things breaking due to not having a posix shell. And zsh can be customized to have most of the niceties of fish anyway. But it is pretty cool how fish comes with so many niceties out of the box!


Well, I like it and that’s a good reason for me.


Parameter expansions don't need to be defensively quoted. That's what got me to switch.


Sure. Some of its features are pretty handy and it is basically fully bash compatible. You don't really loose anything.


I have been using bash for decades, not only on Linux, but also on other UNIX-derived operating systems.

Less than a year ago, I have tried zsh, without a definite intention to switch to it, but eventually I ended always using zsh for interactive use, while continuing to use bash for scripts.

I have benchmarked some scripts with both zsh and bash, but I have not seen any significant difference in speed.

While there are a few scripting features originally introduced by zsh (most of the brace expansion variants), bash has also incorporated them many years ago. Besides those, both bash and zsh implement the ksh93 features, so there is little reason to prefer one or the other. Therefore I have stuck to bash for scripts.

It is hard to say exactly why now I prefer zsh for interactive use, because there is no killer feature, but mostly various small details.

For some reason, zsh seems more responsive, when interactive. I rely a lot on autocompletion and the default autocompletion rules in zsh are more powerful and also the zsh autocompletion seems faster.

While in most cases I prefer the way zsh handles autocompletion, there are times when zsh annoys me by trying to be too smart, e.g. it will never autocomplete "mkdir" with the name of an existing file. I need that frequently, when I want to create a subdirectory in which to move a bunch of related files, with very long names that I do not want to type, but I want to edit slightly to make a name for the new subdirectory, so I have to use a workaround like autocompleting a "ls", then editing it into a "mkdir", while that was not needed in bash.

In zsh I use a much more complex shell prompt that I had used in bash, which displays a lot of useful information in a format that avoids confusion with the command lines or with the text output of the executed commands.

After switching to it in zsh, I have discovered that such a complex shell prompt is also possible in bash. Nevertheless, after using it in bash I have discovered some bash bugs. The too complex shell prompt confused bash and the text cursor became desynchronized with the correct position in certain contexts, so I had to revert in bash to a simple shell prompt.

I think that you should give zsh a try for interactive use. After using it for some days you will see if you prefer it to bash or not.

Now I prefer the interactive zsh, but there are no large differences, bash and zsh are similar and mostly equivalent, because whenever one was improved somehow, the other also copied that feature soon.

I had completely forgotten, but when I have tried for the first time to use zsh as a bash user, I have spent some ten minutes of great confusion, until discovering that I have to add to my ".zshrc" the lines:

bindkey '^[[H' beginning-of-line

bindkey '^[[F' end-of-line

bindkey '^[[3~' delete-char-or-list

in order to have the line editing keys with which I was accustomed.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: