Nowadays I just use fish with the out of box installation and it fits all my needs.
I can write fish, scripting or interactively on my shell without thinking too hard about the syntax, but when scripting in bash I require an example or using my snippets to be sure I'm not shooting myself on the foot or writing something that bash will reject right away.
But yeah the syntax with [[, if fi, while stmt; do; done, "$@", case esac, "${!VAR}" and others makes me long for the day fish shell gets "euo pipefail" mode so I can stop writing bash or || true :)
So we still have this inflection point where scripts eventually have to graduate into a "real" language, and while those languages give us proper data types and structures on one hand, they take away conveniences like pipes with the other. It's 2026, and we managed to crack artificial freakin' intelligence before we got a decently evolved shell into the mainstream. </yells-at-cloud>
/usr/bin/time -f "%e seconds" fish -i -c exit
0.21 secondsI was a bash => zsh/omz person and had these same complaints. But that was 10 years ago. https://github.com/paulirish/dotfiles/blame/main/fish/config...
The baseline fish experience is just better.
It's written in Rust, if you care about that sort of thing (I switched before that was a thing). And for simple one-liners, compatibility actually has improved at least a bit (like you can do && now, which wasn't a thing before).
Write your shell-specific helper scripts or personal scripts in fish, write your portable scripts in Python or Bash. Look, I love standards. Sometimes non-standard things make sense though. Sometimes they even make more sense in the right context.
Or maybe you'll hate it. That's fine. People won't know until they try though.
For something newer and even more different, check out nushell. I don't have much experience with it, but a lot of its ideas are enticing.
I could spend hours figuring out all those things, bit I'd rather use that time for something more important.
This post is explaining how to set up those things. Less than five minutes to read.
OMZ is still easier to set up consistently. That’s why we use it.
If the concern is the bloat of OMZ then make FMZ - fast my zsh - that is just as quick to set up and doesn’t add “bloat”?
It’s a single command to install oh-my-zsh. I can fire it off, check Slack, and come back in 5 minutes. If I have to take 5 minutes to setup it up, I’m just not going to do it.
In your defense I must say I installed starship ages ago but still not migrated to it from powerline-go because I'm lazy.
Hacker News: Where the hackers don't want to think about any of this command-line nonsense because there is important webshit to build.
Some chefs like to spend hours sharpening their knifes with wet stones. Others are just going to run it through a power sharpener and get on their way.
I like to focus my craft in places other than the terminal.
hackernews: where a large portion of programmers are considered inferior because of the domain they work in (the domain where hackernews also lives)
I’ve also worked with some awesome web devs, to be fair.
I could spend that time tinkering with the internals of an ad-hoc informal system cobbled together in the 1970s and held together by spit and glue.
Or I could just not do that.
Also, the implication that fiddling with shell scripts is somehow a better engineering/programming practice than web programming is laughable at best.
And from the article
> Because cloud services are available globally, I've disabled them.
That's some bad defaults right there.
> When you run a command, it also shows how long it took to execute.
No I absolutely don't want this thing done by the author. Now I am fully in the "customize my config" territory.
Also, most of us are unlike the author, and 0.07s vs 0.38s startup time means no difference.
I think the point of the previous comment has been more than clear enough.
That's quite likely a workflow thing. If you are popping up new (transient) terminals frequently, then a ~400ms wait time for each adds up and makes the entire machine feel really slow. I'm willing to wait extra half a second for a new terminal -- once -- after I've changed my autocompletion configs (rebuild + rehash takes a while), but if I had to wait for that long every time I hit Win+enter and wait for the terminal to become active, I'd be irritated pretty damn quickly too.
You get conditioned to immediate responses pretty fast.
There's so many better non-shite alternatives. Just one: Zim aka zimfw is one. It's just so sad that there's such a negative creep energy towards "I tried nothing and did nothing and this is where I am". Bad hacker bad. You deserve no voice.
Configuration is straightforward and easy imo: https://starship.rs/config/
Give it a spin, I think you won't regret it.
Only drawback is that it's not POSIX, no issue for me, but maybe for people who have a lot of muscle memory with bash.
First, there are some ways to make fish more compatible with bash.
If you want to do some shell scripting in fish, or running other people's shell scripts (or commands) this may aid you since you wouldn't have to port them (or take less time to port them over).
You can achieve this with a plugin system such as 'oh my fish' or 'fisher'. But, as always, it adds complexity (and bloat :P), you'll need it on every fish shell (including remote systems), etc.
It is a bit akin to having nvim with plugins versus being able to use vi. Sometimes, you're going to need to be able to use the latter.
Also, to people who recently adopted fish: fish has been made more and more compatible with bash throughout those years.
FWIW, I use fish with starship these days.
and script.sh just starts with #/bin/bash
I'm simple
The way I actually have things setup, in case it helps. I don't change my default shell. I actually default to pretty much working within tmux. So, I kept my default shell to what the OS brings, then in my tmux config, I have,
# set shell
set -g default-shell /opt/homebrew/bin/fish
This means, that when I start my terminal, it drops me to zsh (macOS default). Then when I run tmux, it opens fish. The nice thing is that I inherit the environment of zsh.I have my .zshrc and my .bashrc sourcing a .shellrc file which contains most of my env stuff. This keeps random utilities that write to .bashrc and zshrc working within fish too.
Fish is nicer to script in by far, and you can keep those isolated with shebang lines and still run Bash scripts (with a proper shebang line). The only thing that’s tricky is `source` and equivalents, but I don’t think I’ve ever needed this in my main shell and not a throw-away sub shell.
I guess that somewhat breaks with fish: either you use bash -c '...' from the start, or you adopt the fish syntax, which means you need to convert again when you switch to a (bash) script.
I also don’t trust myself to not screw up anything more complex than running a command on Bash, without the guard rails of something like shellcheck!
I don't care for mile-long prompts displaying everything under the sun, so zsh is plenty fast.
Later I found fizsh, which I love and still use as default shell now. It's basically a configuration around zsh adding the colors, completions, and other good stuff inspired by fish to zsh. Can really recommend it for those who are used to zsh or bash but want their CLI to be more readable. Colors especially help with big command line arguments to show where they start and end, and keeping track of complex stuff like loops and conditional logic in your commands.
https://starship.rs/presets/gruvbox-rainbow
You can see that when the segments are empty, they still appear as a 1-width segment, rather than entirely disappearing.
It also makes you configure many things by hand. powerlevel10k has an interactive wizard that lets you design your prompt one option at a time (do you want a nerd font? do you want it one line or two? etc) but Starship makes you manually write escape codes if your preferences don't match one of the presets.
No judgment, but I do wonder what people like about Starship that makes up for these things.
https://starship.rs/presets/#pastel-powerline
I tried making my own and the config TOML syntax isn't expressive enough to support hiding empty segments.
You're right that it's the thing with the Unicode character as separator, which all the alternatives handle just fine: powerlevel10k, tide, oh-my-posh... it's just everyone seems to love Starship, and that's what confuses me.
I don't know if starship is still using Zle. If so, this should be possible to configure without OMZ.
Nice history, command auto complete, and similar beyond just the looks, out of the box
After installing and adding it to my bashrc, I was wondering was those version numbers and cloud symbols meant. Turns out: Since NodeJS and Python were installed, it found a good idea to print the respective versions. I could not care less about those versions. The other part was that it thought that I would like to see my AWS region. Well, I mean, I have built something with AWS a few years back, and the config file for that still exists, but no, I don't want to see that region every time I open a shell. Finally, the default is to have the prompt in a new line. I think when you have a long prompt that makes sense, and it might also be a taste thing. However, the documentation has this example at the beginning about newlines:
# Inserts a blank line between shell prompts
add_newline = true
So I thought `add_newline = false` should do the trick, but it didn't.Luckily, the AI (GPT-5.2) was pretty good at explaining and giving instructions for changing things. So after 30 minutes, everything was understood and configured to my liking. I like the result, but the default was pretty weird.
oh my zsh can recreate much of the fish functionality while maintaining good bash interoperability.
That already defeats the purpose:
I don't want to copy things around
I never spend time crafting a custom config
I'm joking but on a more serious note, installing a shell as a default shell seems more complicated than copying over your .bashrc
more complicated than copying over your .bashrc
In case you weren't aware, MacOS uses zsh as the default installed shell. The bash version that comes with MacOS is some ancient 3.x version, from 2005.Maybe I'm underinformed, but I don't personally know any Linux users who convert to zsh, instead opting for fish or something else (oilsh? nushell?).
So I removed it, then continued using Zsh and whenever I missed something from before I looked up what it was and installed the plugin easily with Homebrew. The whole process took under an hour. I realised I only needed two or three plugins.
Now my shell is fast, without unnecessary bloat, and does what I need. I’m much more productive and happier, and at the end of the day I don’t really see what’s more important than that (within the scope of the conversation).
OMZ has been working steadily for me for the past 8+ years. Autocomplete, syntax highlighting, and a concise prompt--really all I need.
So I figured out what I was using and created my own very paired down version of what I needed. My boot times are much faster and I’ve been totally happy with it. I also learned a lot more about shell configs as a result.
So I went and had Gemini make me a zsh config with the features I actually use. Took 15 minutes to get all the autocompelte, aliases and search functionality and done.
I stripped out most of the OhMyZsh functions (which is pretty modular given a shell package) and created a smaller, leaner package (leanZSH) having only the known stuff I may use. I have been using it without much complaints.
But I agree that terminal environments have serious shortcomings. I think it's a real shame we haven't created anything else that does what the terminal does, and I think it's mostly for lack of trying.
$ trap '' chld
$ nu -c test
Error: nu::shell::io::uncategorized_error
× I/O error
╰─▶ × failed to get exit code
╭─[source:1:1]
1 │ test
· ──┬─
· ╰── Uncategorized error
╰────
$Why would you want `test -e "$foo"` when you have `$foo | path exists`? Why `test -n "$foo"` when you have an actual == comparison and pattern matching expressions? And you don't have to worry about quoting things just right in any of the situations.
Yes, you need to learn a little bit of a new thing. You can even implement a test function itself if you really want to. But sometimes it's nice to just dump the legacy baggage.
You're replying to someone that says POSIX shells are holding people back, not that the terminal is a bad idea, there are many alternative shells which offer benefits over POSIX shells. fish-shell has everything you want from an interactive shell included, xonsh is a mix Python shell, nushell and elvish are adding types and other things to shell.
The VT protocols that all shells have to confirm with are pretty dated and I'd love to throw them off the roof for something less stateful and with multiple font sizes but there's no arguing that text based interfaces are good.
Nushell is definitely my fav of the set (xonsh is a neat experiment but ultimately is missing pipeline programming that nushell gives....), and I write personal shell scripts for myself mostly in nu.
Aside: for shell scripts, my preference is something like nu, then python + stdlib, giving me argparser etc, then just zsh/bash/whatever. Seriously annoying how POSIX shells do not give good argument parsing, tho I get it's a hard problem
I'd rather just take terminals a step forward, which I agree hasn't happened due to a lack of trying. But the people who aren't trying are the people who are instead tricking out zsh with plugins. I'm a nushell fan myself but my point here is not
> try nushell
but rather,
> be willing to try things that aren't backwards compatible with `sh`
If more people relaxed on that sticking point, we could actually benefit from the excellent post-POSIX work that has been done. As it is, people are reluctant to try new shells for some reason.
This can be disabled fairly trivially. I then alias the update command to a homebrew update alias.
Even better recently I discovered that FreeBSD has a package for it!
`pkg install ohmyzsh` and 5 seconds later it's ready. Plus I figure it's a bit more secure and insulated to any ohmyzsh breaches.
Zimfw definitely has it's own ecosystem, plugins which are zimfw capable. But it's remarkably versatile at bringing in zsh code. Most plugin-systems are pretty ego-centric, demand specific implementations, and zimfw stands out not just for it's ridiculously impressive speed & handling, but for it's versatility too.
Zimfw rocks.
Maybe one day though.
Other than that, oh-my-zsh with git, systemd, and fzf plugins. Saves a lot of typing.
The main selling point for me is how easy it is to setup.
git commit -> gc
git status --short -b -> gsb
git checkout -> gco
systemctl --user restart -> scu-restart
Nothing that you couldn't come up with yourself, but I've been using for so long it has become a standard for me.
The fzf plugin enables a fuzzy finder when you hit ctrl+r or ctrl+t. You need fzf installed.
Slight pain on a mac to get the latest version and use it as terminal shell, but it gets easier everytime I work on a fresh mac.
[1]: https://eli.thegreenplace.net/2013/06/11/keeping-persistent-...
YMMV but I have found using zsh too frictitious to be helpful. Sure, theoretically zsh living in a bash world (lets face it, all scripts are bash) is completely fine but reality seems to differ. Copied a one liner from shell history into your script? Crash. Use arrays? Weird bugs. Use shell builtins? Whoa unexpected interactivity!!! Etc...
Bash is absolutely fine as a default shell. As an added benefit, you don't feel like an invalid once logged in to a container or server.
But yesterday's conveniences become today's essentials, and those who came in after me have their expectations set by the much more sophisticated things available at the time. Like, I'm still flabbergasted by people—working professionals—who go "I can't program without syntax highlighting, autocomplete, and my IDE generally going bing bing wahoo at me as I work, and I don't know how anybody can." We just type the code in. Like we all had to back in the day.
Anyway I can certainly see where someone younger than about 35, or who came to Linux late, would be completely at sixes and sevens without their colorized racing-stripes shell prompt.
$ hyperfine -N "zsh -lc 'exit 0'" "zsh -c 'exit 0'"
Benchmark 1: zsh -lc 'exit 0'
Time (mean ± σ): 54.5 ms ± 6.3 ms [User: 10.2 ms, System: 14.3 ms]
Range (min … max): 38.1 ms … 64.9 ms 78 runs
Benchmark 2: zsh -c 'exit 0' Time (mean ± σ): 6.5 ms ± 1.4 ms [User: 0.8 ms, System: 1.3 ms]
Range (min … max): 3.9 ms … 14.2 ms 424 runs
It's crazy how their startup time is 380 ms, and I suspect something else might be the reason, not just oh-my-zshThat said, the time of `zsh -ic exit` isn't really meaningful metric for measuring the performance of an interactive shell. See https://github.com/romkatv/zsh-bench#how-not-to-benchmark for details.
zmodload zsh/zprof
.. rest of your zsh config ..
zprof
And then restart terminal.It achieves instant startup by rendering the prompt before the full shell initializes. Since adopting it, I am done fiddling with my shell config and the fact that `zsh4humans` is in maintenance-mode is actually an advantage as it keeps me from wasting time refactoring `zshrc`.
>> My workflows involve opening and closing up to hundreds of terminal or tmux tabs a day.
What?!?
Thinking about that I realized I prefer not to use any plugin manager at all.
Shameless plug: I wrote a detailed git prompt in C which is similar to posh-git on Powershell: https://github.com/mahesh-hegde/promptsynth
This sounds like overoptimization on a neglible time loss for what is essentially an unique (and dare I say: broken?) workflow.
I use terminals a lot ... but I work with 4-5 day-persistent terminals that I open once a day and keep in the background. The QoL effects of omz outweigh microtuning startup times significantly.
At first, you need them. You'll fall without it. But if you still rely on them after a while, it's not a good sign.
This investment makes sense for OP who opens hundreds of terminal sessions, but does it make sense to bother about 1s delay when they start the terminal session once in a while? I have several sessions opened all the time, the last time I wasted my 1s on zsh was in 2025 when I rebooted my machine due to a nvidia drivers update.
HN has gone on a decade long crusade against Electron, of course 400ms is a lot.
EDIT: The OP fails to mention zsh profiling: zprof. I discovered that atuin is my biggest waster at the moment with like 20ms and rest of the stuff I could clean up.
(Bonus, I use Zoxide to replace the alt+d cd shortcut as it's much faster, and use https://github.com/Aloxaf/fzf-tab for tab completions in the terminal to become fuzzy, very very useful)
On my machine this is handled in zsh, not fzf (but then fzf still benefits). You can configure your shells to sync without exiting. You may need to run one command (or just hit enter with nothing typed, maybe) for the shell history to catch up, but then it should all be there. Relevant options:
# share history among terminals
setopt share_history
# append to the history instead of overwriting
setopt append_history
# append to history incrementally instead of when the shell exits
setopt inc_append_history
I think finding out about this is why I originally switched from bash to zsh several years ago.
I'm not saying CachyOS is bad, just that it is in my opinion another layer of complexity that may change/deprecate/etc.
Have your lost your old configs that you worked hard on? That's a shame if so. I love moving my configs I've worked hard on to new machines and instantly getting up and running in a now-familiar environment. It saves so much time and effort.
Bigger fish to fry if we're being practical.
`mise use node@latest`
Most tools are now directly fetched from github releases without the need for random shell scripts (which is what asdf plugins are).
It also grew to be a task runner and environment manager. At first you might think this is scope creep but they're both opt in and very elegant additions. I don't want to ramble but let's just say they've solved real problems I've had.
I'm a fan of it, and I can't think of a reason why I would use asdf over mise. Its real competition is nix (+devbox/devenv/flox), devcontainers, and pixi.
GPT-5.2 changed the nvm initialization script to:
export NVM_DIR="$HOME/.nvm"
_nvm_lazy_load() {
unset -f nvm node npm npx _nvm_lazy_load
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
}
nvm() { _nvm_lazy_load; nvm "$@"; }
node() { _nvm_lazy_load; command node "$@"; }
npm() { _nvm_lazy_load; command npm "$@"; }
npx() { _nvm_lazy_load; command npx "$@"; }What I recommend is replacing it with $PATH=(a command to find the nvm default alias directory, detect the verion and load it from that specific version directory directly) so you always have default node in path and then lazy loading only nvm itself, so you can switch when you need to.
Sorry I don’t have the command handy as I’m on mobile but if you paste the above into Opus you’ll get it.
cargo install starship --locked
downloads 336 packages. So much for "minimal". cargo is the new npm
We wouldn't celebrate a C project for specifically holding down to say, 10 source files max. We'd celebrate it separating concerns well instead.
It auto installs everything if you don't have it. Starts effectively instantly.
External dependencies (or remove their line at the bottom)
- [Mise](https://mise.jdx.dev/) fast asdf, runner, and direnv replacement
- [oxide](https://github.com/ajeetdsouza/zoxide) smart and fast cd replacement
-[atuin](https://atuin.sh/) ctrl + r and shell history finder
- [fzf](https://github.com/junegunn/fzf) fuzzy finder
``` # Plugin Manager
declare -A ZINIT ZINIT[NO_ALIASES]=1 ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git" [ ! -d $ZINIT_HOME ] && mkdir -p "$(dirname $ZINIT_HOME)" [ ! -d $ZINIT_HOME/.git ] && git clone https://github.com/zdharma-continuum/zinit.git "$ZINIT_HOME" source "${ZINIT_HOME}/zinit.zsh"
autoload -Uz compinit; compinit
# Plugins zinit light Aloxaf/fzf-tab zstyle ':fzf-tab:' use-fzf-default-opts yes zinit light zdharma-continuum/fast-syntax-highlighting zinit light zsh-users/zsh-autosuggestions
# Starship zinit ice as"command" from"gh-r" \ atclone"./starship init zsh > init.zsh; ./starship completions zsh > _starship" \ atpull"%atclone" src"init.zsh" zinit light starship/starship
zstyle ':fzf-tab:complete:
' fzf-bindings 'shift-tab:toggle' zstyle ':fzf-tab:' switch-group ',' '.' zstyle ':fzf-tab:' continuous-trigger '`'source <(fzf --zsh)
eval "$(mise activate zsh)" eval "$(zoxide init zsh)" eval "$(atuin init zsh --disable-up-arrow)" ```
So far that has been a great move, my terminal tab feel snappy again. One thing I miss (but I’m sure I could find a way to replace it) is `cd ….´
How do you get to hundreds?
I never have more than a one or two dozen terminals at a time, but I definitely open hundred of short-lived ones.
This feels like a strange hang up to me.
Anyway, yeah, all of this adds startup and command invocation time, but the value far outweighs the latency.
Now, I'm deep down the rabbit hole of standardizing all my shells/terminals/configs with Nix. Either a really good or really bad project to start on a Friday night.
setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
bindkey "^R" history-incremental-search-backward
autoload -Uz compinit && compinit
The first one is mentioned in `git-prompt.sh` that comes with git, which needs to be sourced as well. /usr/bin/time -f "%e seconds" zsh -i -c exit
0.04 seconds
I think they are just doing something wrong. Why people are upvoting this nonsenseIt's just a handful of files and I manually source them in my zshrc[2]:
source $ZSH/lib/async_prompt.zsh
source $ZSH/lib/key-bindings.zsh
source $ZSH/lib/completion.zsh
source $ZSH/lib/history.zsh
source $ZSH/lib/git.zsh
source $ZSH/lib/theme-and-appearance.zsh
It's essentially the same as omz setup I was using before, but loads in just ~25ms (Note: it's on a hard drive, with ddr3 ram and 18ms out of that is spent by compinit)It also fixed another issue I had with Oh-My-Zsh: whenever they (very rarely) tweak their default config - it breaks my muscle memory.
[1] https://codeberg.org/janAkali/dotfiles/src/branch/main/confi...
[2] https://codeberg.org/janAkali/dotfiles/src/branch/main/zshrc
Wowsers!
That +0.5 seconds delay will kill cats everywhere. We must microoptimise the startup time of shells!!!
Or ... we could simply use bash and KDE konsole with, say, 10 tabs. That setup works for me since ages; admittedly I use bash just as a wrapper for simple actions as well as calling a gazillion of aliases and mostly ruby scripts that do the real job. But damn I never knew there were guys who were concerned with +0.5 seconds delays caused by oh-my-zsh. The bloat! Oh my godsers!
Yesterday just shy over 50, according to entries from `login` in the system log.
I do launch multiple interpreters just to get a fancy coloful cowsay on each launch. Which involves the fortune program, lolcat (via ruby) and cowsay itself (via Perl). I probably should optimise that into a single C binary for better startup times! :)
I don't use oh my zsh, but on one laptop zsh took 600ms to start. I narrowed it down to a strange "bug": adding even a single empty file to the custom fpath caused the slowdown. It bugged me so bad that I decided to try fish again, but this time for real. And this time it stuck with me. I like its architecture (defining functions to change its look-and-feel - great idea!) and of course its 32 ms startup time.
A reason is that I use i3 workspaces, with each workspace being for different tasks, so I don't want to reuse a terminal that has another context.
One issue with keeping a single shell is that the history is full of irrelevant stuff. If you run commands that take a while and print a lot of output, you want it to be as clean as possible. If I want the beginning of the command, I can scroll to the top, and I don't end up with some unrelated output.
I also take quite notes in vim everywhere, often next to long-running commands, using tmux.
Starting one command, realizing you need info from a previous command, often the fastest way to get that info is to open another terminal and start typing and the copy-pasting the relevant piece of cmd. Or needing the output from another command that's scrolled up in a window. In general you end up with a mosaic of tiles each of which is holding key information. So you inevitably open a new tab to make use of the information in the other 3 or 4 windows.
Shell startup is mainly not about waiting for a few terminals in abstraction, but about the way each shell is just a small piece of a longer live workflow and waiting a second for a shell so that you can fill in a piece of a command feels terrible. I think nushell will help cut down on this unpiped inefficiency, but it's usually much simpler to manually glue bash commands together than to parse text output and pipe.
Could you give some examples of issues you encountered because of that? I've been using fish for about 8 years now I can't remember an instance where that was a problem in interactive use.
Another example is small utilities. I wrote one to login to MySQL DBs at work. We have to use Teleport, which I dislike, and it has MFA. So I made a small SQLite DB that has cluster names, endpoints, and secret ARNs (no actual secrets, only metadata), and then wrote a shell function that uses fzf to parse the SQLite DB contents, then ssh tunnels through an EC2 with Teleport to the selected MySQL DB, using expect with a call to 1Pass to answer the password request, and then picks the first available port >=6033 to connect the mysql client. It also tracks the MySQL DB : port assignments in the SQLite DB and waits for the client to exit so it can tear down the ssh tunnel. The only input I have to do beyond selecting the DB is answering a push notification on my phone for MFA.
> replacing 10-LOC shell scripts with Python
The startup time would drive me insane. I love Python, but it’s not great for stuff like that, IMO.
That's not a problem since it's available and when #/bin/bash or env bash is there, it just works.
My bash scripts are stored in a folder on my PATH, so it all just works.
Also one of may main use case is documenting things other developers can do to make their life easier. There are handful of things where zsh behaves differently than bash. And while those handful of thins are not even a POSIX or shell things, they often come up.
The reality is, every day I’m fighting with “developers” who don’t know what the difference between AWS, Linux, and bash is. Throwing “fish” into the mix seems like I’m just being obtuse for no reason. I have sept hours trying to explain to some dumbass that git-bash on windows is not the same thing as Linux only for them to call me “oh he really cares about ‘bash’”-guy. While claiming they are “Linux developers” as they use macOS.
Which is to say, if you need to run a Bash script, run it via `bash foo.sh` rather than `./foo.sh`. There's no need to limit yourself to a worse shell just because there exist some scripts out there written in that shell's language.
It's not perfect, the lack of HEREDOCs are annoying sometimes, and no background-able blocks (eg `{x}&`) means you can't async things as easily in scripts.
Zsh has a lot of advanced stuff (at least for a shell) that can deliver pretty complex scripting such as throw/catching, mountains of variable flags and switches which I do miss when I write fish scripts but really -- I've abused them a lot over the years and now days I would be more likely to just use a "builds to a single binary" language.
I will probably swap to nushell when it gets a bit more stable (in my experience it's runtime is stable, but it's feature set / command names are still shaking out. I really like it's general ideas though in terms operating on structured data.
For some reason it was slow to load which I found annoying, so I used Claude Code to optimize it. In the end I ended up removing Oh My ZSH entirely, now I have a single .zshrc file that contains everything, and it became much faster.
Similarly I moved from Packer to Lazy.nvim and updated a number of libraries, and from iTerm to Ghostty, Claude Code essentially converted my configs in a matter of minutes
However I agree with other comments that the author's baseline of 380ms is suspicious. I get 150ms (full config, 6 plugins) vs 50ms with no config and plugins.
users.users.yourUser.shell = pkgs.fish;
[0]: https://search.nixos.org/options?channel=unstable&show=users...In the end, I realised nothing was as good (to me) as my original Bash set up. I have all the features I need, it's universally supported, and it's fast.
Tip: Install the post GNU2 version from brew
I have 90 lines zsh config with 3 plugins (compinit, vcs-info, edit-command-line) and startup-exit sequence takes 0.32s.
You learn very quickly where the lags come though when you work on a big old repository (I learned this on Emacs source code) where getting current branch for jujutsu takes ~5 second. Git is faster in this regard but it still is ~0.3s
I'm not fan of starship (I don't use fancy command line variables in general) but many of those issues can be dealt with awesome bkt caching utility [0]. Instead of live reading just let bkt cache it with long TTL with eager async refreshes. My guess is that Starship does exactly that.
Terminals are such a small, unimportant part of my job I barely even think about them.
Win11 Pro is also fine. I spend radically less time fighting Windows than I spend fighting Linux userspace disfunction.
I am also an avid Vim user but I disagree. The default readline is perfectly fine for single line commands (you do have to know your way around some basic commands though C-a/u/k/l/w...). To edit long commands in $EDITOR you can always do C-x C-e in bash/zsh (M-v in Fish). As a matter of fact everytime I pair program with my colleague I always think he is editing those short commands slower than I would have because he has to change modes all the time.
Thanks I didn't know!
Readline settings depend on what you're already used to. If you're comfortable with vi key bindings, then being in normal mode, navigating with `w`/`b`, deleting a word with `dw`, deleting up to a quote with `dt"`, etc., are all done with muscle memory, and should be much faster than learning the equivalent Emacs bindings, pressing unintuitive key chords, or opening the command in an editor. I don't like opening an editor since it's an interruption, and it hides the output of the previous command.
I wish I could have the full power of Vim in my shells. For example, I miss the delete between characters binding. `di"` or `di'` are great for modifying argument values.
/usr/bin/time -f "%e seconds" zsh -i -c exit
0.06 seconds
This is acceptable, maybe the zsh-autocomplete is the problem for author or something else?I originally switched to ZSH + Oh My Shell because it opens so fast. Ideally plugins would initialize asynchronously but it's not very easy with shell scripts I think.
Check out zsh-bench⁽¹⁾ for a more authoritative approach, including first prompt lag, first command lag, input lag and exit lag.
For nixos users: https://discourse.nixos.org/t/using-zsh-with-grml-config-and...
Super easy to setup, and works very well
They all do... if you want the niceties of not having to write your own shell config, what would you expect?
It's funny how many people pick up OMZ or doom emacs because some YouTuber told them to do it, then drop them in 6 months because they're all bloaty.
I have a script for each of my projects that I run when I open a new terminal window (Alacritty). The scripts set up tmux with 3-8 terminals, each terminal launches a components, utility or just sits in a folder from which I later run commands.
Having said that, I use only a few zsh plugins, and have a theme configured to not run commands that add extra latency.
There's quite a few things the OP's post didn't mention about shell history that I think are really important:
setopt HIST_IGNORE_ALL_DUPS # Never add duplicate entries.
setopt HIST_IGNORE_SPACE # Ignore commands that start with a space.
setopt HIST_REDUCE_BLANKS # Remove unnecessary blank lines.
It's possible to roll your own prompt that does helpful things without using starship.Also you can roll your own zsh plugin manager in a few lines of shell scripts, `fast-syntax-highlighting` is a really useful plugin to get real-time feedback when typing commands.
Most of those things are mentioned here https://nickjanetakis.com/blog/i-recently-switched-to-zsh-an..., the post is 5 years old but just about all of that is what I do today still. Since then it has evolved to become better IMO, including using a dedicated Vim zsh plugin which is much improved over the default zsh key binds. Also another plugin to show zsh's tab complete in fzf instead of zsh's window. The tab complete demo video is here https://nickjanetakis.com/blog/hooking-up-fzf-with-zsh-tab-c....
If I'm feeling really fancy I may enable vim bindings and add the fuzzy find plugin, but plain fish is so good on its own.
Some quick troubleshooting many years ago narrowed the vast majority of the problem down to the git plugin, especially for large, old repos.
I disabled the git plugin and everything has been fine ever since.
Figured I'd dig deeper and bring back the current branch name without the bloat at some point, but it hasn't bothered me enough to do it.
I have used this for a long time, never understood how people would put all of git in between them and the next prompt.
~150ms with minimal setup is good enough for me, although I would prefer <50ms.
You'll never get back those milliseconds. Just like I can't get back the time I wasted reading this article.
time zsh -i -c exit
zsh -i -c exit 0.12s user 0.09s system 81% cpu 0.276 total
~I describe my setup and how to use it on a fresh MacBook here: https://github.com/agrounds/dotfiles
Swizec•16h ago