Bash vs Zsh for scripting

Zsh is a great interactive shell but Bash is the better choice for portable shell scripts. Here is why, with concrete examples of where Zsh-isms break.

Tldr

Use Zsh for your interactive shell if you like it; use Bash for scripts. Zsh has nicer interactive features but its scripting language differs from Bash in subtle ways (word splitting defaults, glob behavior, array indexing) that break portability. Bash is preinstalled on virtually every Linux distro; Zsh is not.

Sections

Heading

Where they diverge

Body

Zsh does NOT split unquoted variables by default — `$var` stays as one word even if it contains spaces. Bash splits on IFS. Zsh arrays are 1-indexed; Bash arrays are 0-indexed. Zsh has its own glob qualifiers and recursive globs (**/*.txt) without needing globstar. Each of these is a source of subtle bugs when copying scripts between shells.

Heading

Where Bash wins for scripts

Body

Ubiquity — Bash is on every Linux distribution, every cloud VM image, every CI runner. macOS still ships Bash (an old version, but it is there). Zsh is the default interactive shell on macOS now but is not guaranteed on Linux. If you write a script that may run on someone else's machine, Bash gives you the broadest compatibility.

Heading

Where Zsh wins for interactive use

Body

Better tab completion, themeable prompts (powerlevel10k, oh-my-zsh), recursive globs without ceremony, spelling correction, shared command history across sessions. None of these matter inside a script — they matter at the prompt.

Heading

Migration tips

Body

If you maintain a Zsh script and want to make it portable, replace `${array[1]}` with `${array[0]}`, quote every variable expansion ("$var" not $var), replace **/*.ext with `find . -name "*.ext"`, and run it through shellcheck with --shell=bash.

Verdict

Write scripts in Bash, use Zsh interactively if you like it. The 30 minutes of "Zsh is so nice" do not pay back the hours of debugging portability bugs.

Faq

Q

Is Zsh faster than Bash for scripts?

A

Marginally for some operations, slower for others. The difference rarely matters compared to the cost of forked subprocesses inside the script.

Q

Can I use a Bash script in Zsh?

A

If the shebang is #!/usr/bin/env bash and bash is installed, yes — the shebang determines the interpreter regardless of your interactive shell.

Q

What about fish?

A

Fish is not POSIX-compatible at all — scripts are not portable between fish and Bash. Use fish interactively if you like it; do not write production scripts in it.