Bash, Dash, and Common Shell Packages
Overview
On Linux systems, names such as bash, dash, sh, zsh, and fish often appear together. They are all shells: command interpreters between the user and the operating system.
A shell is responsible for several things:
- Reading commands entered by the user.
- Expanding variables, pipelines, redirections, and wildcards.
- Finding and executing external programs.
- Providing scripting language features.
- Managing interactive sessions, such as history, completion, and prompts.
In simple terms:
User command -> Shell parses it -> Kernel/program executes it
What is bash?
bash stands for Bourne Again SHell.
It is the GNU shell implementation and is the default interactive shell on many Linux distributions.
Common paths:
/bin/bash
/usr/bin/bash
On Debian and Ubuntu, the package name is usually:
bash
You can check it with:
dpkg -S /bin/bash
apt show bash
Features of bash
bash is feature-rich. It works well as an interactive shell and is also suitable for complex scripts.
Common features include:
- Command history.
- Tab completion.
- Command aliases with
alias. - Arrays.
[[ ... ]]conditional expressions.(( ... ))arithmetic expressions.- Brace expansion, such as
{1..5}. - Process substitution, such as
<(cmd). - Startup files such as
.bashrcand.bash_profile.
Example:
#!/usr/bin/env bash
names=(alice bob charlie)
for name in "${names[@]}"; do
if [[ "$name" == a* ]]; then
echo "match: $name"
fi
done
This script uses Bash arrays and [[ ... ]], so it is not a pure POSIX sh script.
What is dash?
dash is usually expanded as Debian Almquist Shell.
It is a small, fast shell that closely follows the POSIX shell standard.
Common paths:
/bin/dash
/usr/bin/dash
On Debian and Ubuntu, the package name is usually:
dash
You can check it with:
dpkg -S /bin/dash
apt show dash
Features of dash
dash is not designed to provide a rich interactive experience. Its main goal is to execute standard shell scripts quickly.
Its main characteristics are:
- Fast startup.
- Small size.
- Few dependencies.
- Good fit for system startup scripts.
- Mostly follows POSIX
shsyntax. - Does not support many Bash-specific extensions.
For example, this POSIX-style script works well with dash:
#!/bin/sh
name="alice"
if [ "$name" = "alice" ]; then
echo "hello $name"
fi
However, these Bash-specific constructs usually do not work in dash:
[[ "$x" == foo* ]]
array=(a b c)
echo ${array[0]}
for i in {1..5}; do echo "$i"; done
Relationship between /bin/sh, bash, and dash
Many scripts start with:
#!/bin/sh
This means the script should be interpreted by /bin/sh.
However, /bin/sh is usually not a separate shell implementation. It is commonly a symbolic link.
On Debian and Ubuntu, it usually points to dash:
/bin/sh -> dash
On some other distributions or older systems, it may point to bash:
/bin/sh -> bash
Therefore, the same script:
#!/bin/sh
may be executed by different shells on different systems.
This is why shell script compatibility matters.
Why Ubuntu and Debian use dash as /bin/sh
The main reasons are performance and system startup speed.
Many system scripts use:
#!/bin/sh
If these scripts only use POSIX shell syntax, there is no need to start a larger and more feature-rich shell like bash.
dash starts faster and has lower overhead for simple scripts, so Debian and Ubuntu commonly use it as the default /bin/sh.
This does not mean bash is obsolete. In practice:
- Interactive terminals still often use
bashby default. - System scripts that use
/bin/shmay be executed bydash. - Scripts that require Bash features should explicitly use
#!/usr/bin/env bashor#!/bin/bash.
Interactive shells and scripting shells
Shells are often used in two different contexts.
Interactive shells
The command-line environment you see after opening a terminal is an interactive shell.
It emphasizes:
- Command completion.
- History.
- Prompt customization.
- Keyboard shortcuts.
- Plugin ecosystems.
Common choices include:
bashzshfish
Scripting shells
The shell used to execute scripts usually emphasizes:
- Compatibility.
- Portability.
- Startup speed.
- Stable syntax.
Common choices include:
/bin/shbashdashbusybox sh
Common shell packages
The following table summarizes common shells on Linux.
| Shell | Common package name | Main characteristics | Suitable use cases |
|---|---|---|---|
bash |
bash |
Feature-rich, compatible, mature ecosystem | Default terminals and complex scripts |
dash |
dash |
Small, fast, close to POSIX | /bin/sh and system scripts |
zsh |
zsh |
Strong interactive experience and plugin ecosystem | Daily terminals and developer environments |
fish |
fish |
Friendly defaults and modern syntax, but not POSIX-compatible | Interactive terminals |
ksh |
ksh / mksh |
KornShell family with a long history | Unix scripts and compatibility environments |
mksh |
mksh |
MirBSD Korn Shell, lightweight | Embedded systems and compatible scripts |
busybox ash |
busybox |
Lightweight shell bundled with BusyBox | Containers, initramfs, and embedded systems |
tcsh |
tcsh |
Improved C shell | Older Unix environments and specific user preferences |
zsh
zsh is a powerful interactive shell.
It supports some sh and bash-style syntax, but it is not a complete drop-in replacement for Bash.
Its strengths are mostly in interactive usage:
- Powerful completion system.
- Themes and plugins.
- Spelling correction.
- Advanced globbing.
- Often used with Oh My Zsh.
Installation example:
sudo apt install zsh
Check its path:
which zsh
Change the default login shell:
chsh -s /usr/bin/zsh
fish
fish stands for Friendly Interactive SHell.
It focuses on a friendly interactive experience out of the box.
Advantages:
- Autosuggestions.
- Syntax highlighting by default.
- Simple configuration.
- Good user experience.
Its limitations are also clear:
- Its syntax is not compatible with POSIX
sh. - Many Bash scripts cannot be executed directly by
fish. - It is better as an interactive shell for humans than as a general-purpose script interpreter.
Installation example:
sudo apt install fish
BusyBox ash
BusyBox is a project that combines many Unix utilities into a single executable.
It is common in:
- Container images.
- initramfs environments.
- Embedded Linux systems.
- Router systems.
- Alpine Linux.
The common shell included with BusyBox is ash.
For example, on Alpine Linux:
/bin/sh
usually points to BusyBox ash.
Like dash, it is lightweight and suitable for resource-constrained environments, but it does not support the full set of Bash extensions.
How to write the shebang
The #! line at the beginning of a script is called a shebang. It specifies which interpreter should run the script.
POSIX shell scripts
If the script only uses POSIX sh syntax, prefer:
#!/bin/sh
This is portable and can be executed by dash, Bash in sh mode, BusyBox ash, and other POSIX-compatible shells.
Bash scripts
If the script uses Bash features, explicitly write:
#!/usr/bin/env bash
or:
#!/bin/bash
Do not write:
#!/bin/sh
and then use Bash-specific features such as arrays, [[ ... ]], source, or function.
Such scripts often fail on systems where /bin/sh points to dash.
Common compatibility issues
source vs .
Bash commonly uses:
source ./env.sh
In POSIX sh, use:
. ./env.sh
[[ ... ]] vs [ ... ]
Bash supports:
if [[ "$name" == a* ]]; then
echo yes
fi
In POSIX sh, use case for pattern matching:
case "$name" in
a*) echo yes ;;
esac
For simple string comparison, use:
if [ "$name" = "alice" ]; then
echo yes
fi
Arrays
Bash supports arrays:
items=(a b c)
echo "${items[0]}"
POSIX sh does not have Bash-style arrays.
If you need arrays, using Bash explicitly is usually clearer.
Differences in echo behavior
Different shells handle echo -e and backslash escapes differently.
For portable scripts, prefer printf:
printf '%s\n' "hello"
How to inspect shells on your system
Show the current login shell:
echo "$SHELL"
Show the currently running shell process:
ps -p $$ -o comm=
Show where /bin/sh points:
ls -l /bin/sh
Show command paths:
command -v bash
command -v dash
command -v sh
On Debian and Ubuntu, find which package owns a file:
dpkg -S /bin/bash
dpkg -S /bin/dash
dpkg -S /bin/sh
How to choose
Use these practical rules.
Daily terminal use
Recommended choices:
bash: safe, common, and well documented.zsh: better interactive experience and plugin ecosystem.fish: friendly defaults, but not compatible with traditional shell syntax.
System scripts
Recommended choices:
- Simple and portable scripts:
#!/bin/sh. - Scripts that require Bash features:
#!/usr/bin/env bash.
Containers and embedded systems
Recommended choices:
dash- BusyBox
ash - POSIX
sh-style scripts.
Complex automation scripts
Recommended choices:
bash- or a language better suited to complex logic, such as Python, Go, or Perl.
Key differences
| Item | bash |
dash |
|---|---|---|
| Purpose | Feature-rich shell | Lightweight POSIX shell |
| Interactive experience | Strong | Weak |
| Startup speed | Slower | Fast |
| Scripting features | Rich, with many extensions | Minimal, POSIX-oriented |
| Good default terminal | Yes | Usually no |
Good /bin/sh implementation |
Possible, but heavier | Very suitable |
| Bash arrays | Supported | Not supported |
[[ ... ]] |
Supported | Not supported |
| POSIX script compatibility | Good, but Bash extensions are tempting | Good for checking portability |
In one sentence:
bashis good for humans and complex scripts, whiledashis good for quickly executing standardshscripts.
Practical advice
- If a script starts with
#!/bin/sh, only use POSIXshsyntax. - If a script uses Bash features, explicitly use
#!/usr/bin/env bash. - Do not assume
/bin/shis always Bash. - On Ubuntu and Debian,
/bin/shis likely to bedash. - For portable scripts, prefer
printfinstead of relying onecho -e. - For complex logic, do not force everything into shell scripts. Use Python or another suitable language when appropriate.
Takeaway
There is not just one shell implementation.
bash, dash, zsh, fish, and BusyBox ash are shells with different design goals:
bash: general-purpose, powerful, and commonly used by default.dash: small, fast, and suitable for/bin/sh.zsh: strong interactive experience.fish: friendly, but not POSIX-compatible.- BusyBox
ash: lightweight and suitable for containers and embedded systems.
The key is to distinguish between two questions:
Is this an interactive shell for humans?
Or is this an interpreter for scripts?
Once that distinction is clear, choosing the right shell becomes much easier.