The shell is the program that reads your commands and runs them. Linux offers several. Which one you use matters in two different ways: interactively (comfort, completion, prompts) and in scripts (portability and correctness). Here’s how the common shells differ.
At a glance
| Shell | Type | Best for | Notes |
|---|---|---|---|
| sh | POSIX standard (a specification) | Portable scripts | On Debian/Ubuntu, /bin/sh is dash; on RHEL it’s bash in POSIX mode |
| dash | Minimal POSIX shell | Fast system scripts | No bash extensions (arrays, [[ ]]) |
| bash | POSIX + many extensions | Default login shell on most distros; scripting | The one to know for servers |
| zsh | bash-like + powerful extras | Interactive use | macOS default; Oh My Zsh plugins |
| fish | Not POSIX-compatible | Friendly interactive use | Autosuggestions out of the box; different script syntax |
Check your shells
echo $SHELL # your login shell
echo $0 # the shell you're in right now
ls -l /bin/sh # what sh points to
cat /etc/shells # installed, allowed shells
Change your default shell
sudo apt install zsh
chsh -s /usr/bin/zsh # for yourself (log out and back in)
sudo chsh -s /bin/bash alice # for another user
On servers, keep root’s shell as bash (or the distribution default): recovery tools and many scripts assume it.
Scripting: the shebang decides
The first line of a script chooses the interpreter, regardless of your interactive shell:
#!/bin/bash # bash features allowed
#!/bin/sh # POSIX only: portable, and runs with dash on Debian/Ubuntu
#!/usr/bin/env bash # finds bash in PATH (common on macOS/BSD)
Common bash-only features that break under sh/dash:
| Bash feature | POSIX alternative |
|---|---|
[[ $a == b* ]] |
case $a in b*) … ;; esac |
Arrays arr=(a b c) |
Positional parameters, or separate variables |
function name { } |
name() { } |
source file |
. file |
$(< file) |
$(cat file) |
echo -e |
printf |
{1..10} |
seq 1 10 |
Cron runs commands with /bin/sh by default. That’s a frequent cause of “works in my terminal, fails in cron”. See cron environment variables.
Check scripts with ShellCheck (sudo apt install shellcheck, then shellcheck script.sh). It catches portability problems and common bugs. See Bash scripting tutorial.
Interactive comfort
- bash: solid, everywhere. Improve it with a good prompt, aliases, and
historysettings. See alias command and history command. - zsh: better completion, spelling correction, shared history, and themes and plugins via Oh My Zsh. See zsh and Oh My Zsh.
- fish: autosuggestions and syntax highlighting with no configuration. But fish isn’t POSIX-compatible, so bash scripts and some copy-pasted snippets (variable assignments like
VAR=value,forloops, here-documents) need rewriting or running withbash -c. See fish shell.
A good compromise for servers: use zsh or fish interactively on your own account, while keeping scripts in bash or POSIX sh.
Config files
| Shell | Interactive config |
|---|---|
| bash | ~/.bashrc (and ~/.bash_profile / ~/.profile for login shells) |
| zsh | ~/.zshrc |
| fish | ~/.config/fish/config.fish |
Quick reference
| Need | Use |
|---|---|
| Portable script | #!/bin/sh + POSIX syntax |
| Server scripts with arrays etc. | #!/bin/bash |
| Nicer interactive shell | zsh (Oh My Zsh) or fish |
| Check your shell | echo $0, echo $SHELL |
| Change default | chsh -s /usr/bin/zsh |
| Lint scripts | shellcheck |
Related: environment variables on Linux and Linux terminal shortcuts.