While zsh markets itself as "fully backwards-compatible," there are subtle but critical differences that matter in production environments:
# Bash handles array indices differently
arr=(a b c)
echo ${arr[-1]} # Works in zsh but fails in bash (pre-4.0)
# Process substitution behavior differs
diff <(sort file1) <(sort file2) # More reliable in bash for large files
Bash consistently outperforms zsh in:
- Startup time (critical for short-lived processes)
- Memory usage (important for embedded systems)
- Pipeline execution (noticeable in complex scripts)
# Test startup time comparison
time for i in {1..1000}; do bash -c ":"; done
time for i in {1..1000}; do zsh -c ":"; done
Bash maintains stricter POSIX compliance which is crucial for:
# Portable shebang lines
#!/bin/sh vs #!/bin/zsh
# This Dockerfile snippet demonstrates strict POSIX needs
FROM alpine
RUN apk add bash
COPY script.sh # Requires POSIX-compliant syntax
In corporate IT ecosystems:
- Default shell on RHEL/CentOS remains bash
- Security tools often assume bash behavior
- Existing infrastructure scripts (CI/CD) frequently require bash
# Example of security-sensitive bashism
restricted_shell() {
set -o restricted
# This protection works differently in zsh
}
Surprisingly, bash includes functionality not in zsh:
# Associative arrays before zsh implemented them
declare -A arr=([key1]=val1 [key2]=val2)
# Process substitution with coprocesses
coproc myproc { sleep 5; echo done; }
The shell landscape evolves constantly, but bash remains the pragmatic choice for system-level scripting where performance, compatibility, and predictability outweigh interactive convenience.
While zsh markets itself as "fully backward-compatible" with bash, there are critical edge cases where this breaks down in real system administration scenarios:
#!/bin/bash
# This will fail in zsh due to different array handling
declare -A associative_array=([key1]="value1" [key2]="value2")
for key in "${!associative_array[@]}"; do
echo "$key - ${associative_array[$key]}"
done
Bash consistently outperforms zsh in:
- Startup time (critical for short-lived scripts)
- Memory footprint (important in container environments)
- Subshell execution speed
Bash adheres closer to POSIX standards, making it the safer choice for:
#!/bin/sh
# This portable shebang works better with bash
while IFS= read -r line; do
process "$line"
done < "input.txt"
Bash remains the default shell on:
- Most Linux distributions (including RHEL/CentOS)
- BSD systems
- Docker base images
- CI/CD environments
Surprisingly, bash has some unique capabilities:
#!/bin/bash
# Process substitution works more reliably
diff <(sort file1) <(sort file2)
# Better handling of SIGCHLD traps
trap 'cleanup' CHLD
Zsh shines in interactive use cases with:
- Better tab completion
- Theming capabilities
- Interactive globbing