Bash vs sh vs zsh vs fish

3 minute read

There are many shells available on Linux and macOS. Each makes different trade-offs between portability, features, and ease of use. Knowing the difference helps you pick the right one for each situation.


POSIX sh — Maximum Portability

sh is the POSIX standard shell — the baseline that every UNIX-like system must provide. Scripts written in POSIX sh will run on Linux, macOS, BSDs, and even some embedded systems.

#!/bin/sh
# This script runs on virtually any UNIX-like system
name="Alice"
echo "Hello, $name"

What sh does NOT have:

  • Arrays
  • [[ ]] (only [ ])
  • $'...' syntax
  • local variable declarations (some shells support it, not required by POSIX)
  • Process substitution <(cmd)

When to use sh: When your script needs to run on systems where Bash is not guaranteed — like Alpine Linux containers, legacy systems, or /etc/init.d/ scripts.

On Ubuntu, /bin/sh is actually dash — a faster, minimal POSIX shell, not Bash.


Bash — The Linux Standard

Bash (Bourne Again Shell) is the default shell on most Linux distributions and the scripting standard for DevOps and sysadmin work.

#!/usr/bin/env bash
# Bash-specific features
declare -A config           # associative array (not in sh)
config[host]="localhost"
config[port]="5432"

files=(/etc/*.conf)         # array from glob
echo "Found ${#files[@]} config files"

[[ "$1" =~ ^[0-9]+$ ]] && echo "Numeric argument"   # regex in [[

What Bash adds over sh:

  • Arrays (indexed and associative with declare -A)
  • [[ ]] with regex support (=~)
  • (( )) arithmetic
  • mapfile / readarray
  • Brace expansion: {a,b,c}, {1..10}
  • Process substitution: <(cmd), >(cmd)
  • $'...' escape sequences: $'\n', $'\t'

When to use Bash: For all your scripts unless you specifically need maximum portability. For interactive use on Linux. For all DevOps scripting, CI/CD scripts, and automation.


zsh — macOS Default

zsh (Z Shell) has been the default shell on macOS since Catalina (2019). It is Bash-compatible for most everyday use, with a richer feature set.

# zsh-specific features
setopt autocd              # type directory name to cd into it
setopt globdots            # include hidden files in globs
bindkey -v                 # vi key bindings in zsh

# Better tab completion
autoload -Uz compinit && compinit

What zsh adds:

  • Better interactive tab completion (context-aware, menu-driven)
  • Spell correction for mistyped commands
  • Shared command history across multiple terminal sessions
  • Richer glob patterns (e.g., **/*.log without globstar)
  • oh-my-zsh plugin ecosystem — themes, Git prompt, hundreds of plugins

When to use zsh: As your interactive shell on macOS or if you prefer it on Linux. Do NOT use zsh-specific syntax in scripts you intend to share or run on Linux servers — use Bash for scripts.


fish — Friendly Interactive Shell

fish (Friendly Interactive Shell) is designed for usability out of the box, with no configuration required.

# fish syntax is different from bash — NOT POSIX compatible
function greet
    echo "Hello, $argv[1]"
end

greet "Alice"

What fish offers:

  • Autosuggestions as you type (grey ghost text showing the likely completion)
  • Syntax highlighting in the prompt (invalid commands appear red)
  • Browser-based configuration: fish_config
  • No need to learn configuration — it works well immediately

What fish does NOT have:

  • POSIX compatibility (different syntax for variables, loops, functions)
  • It cannot run most Bash scripts without modification

When to use fish: As your personal interactive shell if you prefer the experience. Never for scripting — always write scripts in Bash or sh.


dash — The Fast POSIX Shell

dash is the default /bin/sh on Ubuntu and Debian. It starts and runs scripts significantly faster than Bash because it implements only POSIX sh with no extras.

# Ubuntu: /bin/sh is dash
$ ls -la /bin/sh
lrwxrwxrwx 1 root root 4 Jan  1  2023 /bin/sh -> dash

When you see dash: When system startup scripts (/etc/init.d/) or package manager scripts run — they use /bin/sh for speed. They do not use Bash features.


Comparison Table

Shell POSIX? Arrays? Interactive Scripting Best For
sh / dash ✅ Yes ❌ No ⚠️ Basic ✅ Portable System scripts, containers
bash ✅ Yes ✅ Yes ✅ Good ✅ Standard All scripting, DevOps
zsh ⚠️ Mostly ✅ Yes ✅ Excellent ⚠️ Non-portable macOS daily use
fish ❌ No ✅ Yes ✅ Excellent ❌ Non-portable Personal interactive use

The Golden Rule

Interactive shell: use whatever you prefer (zsh or fish are great).
Scripts: always use #!/usr/bin/env bash (or #!/bin/sh for max portability).

Never write a script in fish syntax and expect it to run on a Linux server.


← Back to What is a Shell Next → Bash Versions

Updated: