⚖️ Bash vs Dash in Scripts
Understanding the differences between Bash and Dash is essential for writing portable, predictable, production‑grade shell scripts.
Although both can execute shell code, they serve fundamentally different roles in modern systems.
🎓 Who This Is For
- Engineers writing
/bin/sh scripts
- DevOps/SRE teams maintaining automation across multiple Linux distributions
- Developers migrating bash scripts to POSIX sh
- Anyone debugging portability issues between shells
🧩 Role in the Ecosystem
Bash
- Default interactive shell on many Linux distributions
- Rich feature set (arrays,
[[ ]], process substitution, brace expansion)
- Common in tutorials, blog posts, and legacy scripts
- Not always available in minimal/container images
Dash
- Default
/bin/sh on Debian and Ubuntu
- Extremely fast and strictly POSIX compliant
- Ideal for system scripts and CI/CD
- Minimal feature set (no arrays, no
[[ ]], no process substitution)
🧩 Key Differences
1. POSIX Compliance
- Dash → strict POSIX
- Bash → POSIX + many extensions
- Dash starts significantly faster
- Ideal for short‑lived scripts (system boot, CI/CD)
3. Feature Set
- Bash supports arrays, associative arrays,
[[ ]], brace expansion, <( )
- Dash supports only POSIX features
4. Availability
- Dash is always present on Debian/Ubuntu as
/bin/sh
- Bash may be missing in minimal images (Alpine, BusyBox)
🔧 Practical Examples
Bash‑only syntax (NOT portable):
| if [[ $var == foo* ]]; then
echo match
fi
|
| arr=(one two three)
echo "${arr[1]}"
|
Portable POSIX syntax (works in Dash):
| if [ "${var#foo}" != "$var" ]; then
echo match
fi
|
| set -- one two three
echo "$2"
|
| sort a >a.sorted
sort b >b.sorted
diff a.sorted b.sorted
|
⚠️ Limitations & Pitfalls
Bash
- Scripts silently break when run under
/bin/sh on Debian/Ubuntu
- Bashisms often go unnoticed until CI/CD fails
- Not available in Alpine/BusyBox unless installed manually
Dash
- No arrays
- No
[[ ]]
- No
${var//pattern/repl}
- No process substitution
- Less forgiving than Bash
🧠 When to Use Bash
- Internal tooling where Bash is guaranteed
- Developer machines
- Scripts requiring arrays,
[[ ]], or advanced features
- Complex logic before rewriting in another language
🧠 When to Use Dash
- System scripts intended for
/bin/sh
- CI/CD pipelines requiring speed and portability
- Minimal or containerized environments
- Scripts that must run across multiple distributions
✅ Best Practices
- Use
#!/bin/sh for portable scripts
- Use
#!/usr/bin/env bash only when Bash features are required
- Test portability explicitly:
- Avoid Bash‑only constructs in
/bin/sh scripts
- Treat Dash as a portability validator
🧪 Testing Scripts
| bash -n script.sh # bash syntax check
dash -n script.sh # dash syntax check
shellcheck script.sh # static analysis
|
🧠 Summary
Bash is powerful and feature‑rich, but not universal.
Dash is fast, minimal, and strictly POSIX.
Use Bash when you need advanced features — use Dash when you need portability, speed, and predictability.