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 history settings. 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, for loops, here-documents) need rewriting or running with bash -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

See .bashrc vs .bash_profile.

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.

  • Linux
  • Bash
  • Shell