Bash & the POSIX Shell Module 1 – Start here: the shell, the terminal and your first script
Shells, terminals and which Bash you have
How a terminal, a shell and the programs it runs differ, how to tell which shell and Bash version is running, and how to get Bash 5.3 on any system.
What you will learn
- Explain the difference between a terminal emulator, a shell and the programs the shell runs
- Identify the running shell and its version with $0, $BASH_VERSION and bash --version
- Set up Bash 5.3 on Linux, macOS (Homebrew) or Windows (WSL or Git Bash)
What you’ll learn
What you will learn
- Explain the difference between a terminal emulator, a shell and the programs the shell runs
- Identify the running shell and its version with $0, $BASH_VERSION and bash --version
- Set up Bash 5.3 on Linux, macOS (Homebrew) or Windows (WSL or Git Bash)
On this page
A brand-new Mac answers bash --version with version 3.2.57, while the current Bash is 5.3, and a script that uses a
feature newer than that old copy stops with an error the moment it runs there. Before you write a single script, it
pays to know what is drawing the text on your screen, which shell reads your commands and which version it is.
Below you will step through what happens when you press Enter, run one file under three different shells and compare what each reports, ask Bash for its version four ways, write a three-line guard that stops an old Bash politely, and set up Bash 5.3 on Linux, macOS or Windows.
A terminal draws text; the shell reads and runs your commands
When you type ls -l and press Enter, three different programs take part. The
terminal emulator: The program that shows a text window, draws the characters programs write and passes your keystrokes on, such as Terminal on macOS or Windows Terminal. It runs no commands itself., such as Terminal on macOS or Windows Terminal, only draws
characters and passes on your keystrokes. The shell: The program that reads command lines, expands them and starts the programs they name, then waits for them to finish. Bash, dash and zsh are shells., here Bash, reads the line, splits it into
words, finds the program called ls and starts it. The program does the actual work and writes its output back to
the terminal. Step through the six moments of that one command:
The drawing shows the whole scene; its 6 steps are listed below.
Every step as text
- You type and press Enter. The terminal shows each key you press and sends the characters to the shell. It does not know what ls means; it only draws text and passes on keystrokes.
- The shell reads the line. Bash reads the whole line, splits it into the words ls and -l, and applies its expansions. The first word is the name of the command to run.
- The shell starts a program. Bash finds ls in one of the folders listed in PATH and starts it, handing it the word -l as its argument. Bash then waits for it to finish.
- The program writes the output. The ls program does the actual work. It reads the folder and writes the listing straight to the terminal, which draws it.
- The program exits. When ls finishes it ends with an exit status, 0 for success. Bash stores it in the special parameter $? so the next command can test it.
- The shell is ready again. Bash prints its prompt and waits for the next line. The terminal never ran a command; the shell started a program and the program did the work.
The terminal never ran anything: it only displayed what the shell and ls produced. That is why you can run Bash in
any terminal app, and why changing the terminal’s colours or font changes nothing about how your commands behave.
Calling the terminal window Bash
Wrong: “I installed a new terminal, so now I have a new Bash”. Right: the terminal and the shell are separate programs. A new terminal app still starts whatever shell your account uses, and a new Bash works in your old terminal.
Bash, dash and zsh are different shells, and a script needs the right one
Several shells exist, and they share a common core. POSIX.1-2024, published by The Open Group and the IEEE as Issue 8
of their Base Specifications, defines a standard command interpreter, the sh language. Bash implements that language
and adds much more, such as arrays and the [[ ]] test. The man page of dash, a small shell, calls it a command
interpreter that takes in only the features POSIX designates, plus a few Berkeley extensions. And zsh is another large
shell; Apple’s support page says that from macOS 10.15 a Mac uses zsh as its default login and interactive shell.
| Shell | Where you meet it | Its part in this track |
|---|---|---|
| Bash 5.3 | Linux systems, Homebrew on macOS, WSL and Git Bash on Windows | The language every lesson teaches |
| dash | A small shell that keeps to the POSIX features | The check that a script is plain POSIX sh |
| zsh | The default login and interactive shell of macOS from 10.15 | Where many Mac users type, though scripts name bash |
The file below prints what the shell running it says about itself. The same file is then run by GNU Bash 5.3.20, by
macOS’s own /bin/bash and by dash:
#!/usr/bin/env bash
# Which shell is running this file, and which version is it?
echo "name: $0"
echo "version: ${BASH_VERSION:-not Bash}"
echo "major: ${BASH_VERSINFO:-none}" from session import files, run
# The same file, run by three shells: GNU Bash 5.3.20, macOS's own /bin/bash and dash.
files("which-shell.sh")
run("""
bash which-shell.sh
/bin/bash which-shell.sh
dash which-shell.sh
""") Output
$ bash which-shell.sh name: which-shell.sh version: 5.3.20(1)-release major: 5 $ /bin/bash which-shell.sh name: which-shell.sh version: 3.2.57(1)-release major: 3 $ dash which-shell.sh name: which-shell.sh version: not Bash major: none
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 which_shell_session.py
Bash 5.3.20 reports major version 5 and macOS’s copy reports 3. Dash leaves BASH_VERSION empty, so the file prints
the fallback after :- instead. A script written for Bash 5 may therefore work in the first shell, fail in the second
and fail differently in the third, which is why a script states the shell it needs in its first line, the subject of
this module’s last lesson.
Checkpoint
Check: Terminal, shell and program · Bash, dash, zsh and POSIX sh
Four checks tell you which Bash is running
You can ask a running Bash about itself in several ways. $0 holds the name the shell was started with,
$BASH_VERSION the full version, and the array BASH_VERSINFO its parts, so ${BASH_VERSINFO[0]} is the major
version. bash --version asks the first bash on your PATH, and type -a bash lists every bash the shell can
find, in the order it would use them. Here they are, typed into an interactive Bash 5.3.20:
from session import run
# Four ways to ask which Bash you have, typed into an interactive Bash 5.3.20.
run("""
echo "$0"
echo "$BASH_VERSION"
echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"
bash --version | head -n 1
type -a bash
echo "$SHELL"
""") Output
$ echo "$0"
bash
$ echo "$BASH_VERSION"
5.3.20(1)-release
$ echo "${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}"
5.3
$ bash --version | head -n 1
GNU bash, version 5.3.20(1)-release (aarch64-apple-darwin25.6.0)
$ type -a bash
bash is …/bash
bash is /bin/bash
$ echo "$SHELL"
/bin/zsh
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 find_bash_session.py
Two lines need care. type -a bash found two copies: the 5.3.20 build first and macOS’s /bin/bash second, so typing
bash runs the first. And $SHELL printed /bin/zsh, because SHELL holds your login shell: The shell your account starts when you log in, recorded in the SHELL variable. It need not be the shell that is running a given script., the one your account
starts, not the shell that is running now; on this Mac that is zsh, although Bash ran every line.
A script can check the version itself and stop before it fails halfway. This guard needs Bash 4 or later:
#!/usr/bin/env bash
# Stop at once, with a clear message, when an older Bash runs this script.
if [ -z "${BASH_VERSINFO:-}" ] || [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
echo "This script needs Bash 4 or later; this is ${BASH_VERSION:-not Bash}." >&2
exit 1
fi
echo "Bash ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}: new enough" from session import files, run
# The guard passes on Bash 5.3.20 and stops macOS's Bash 3.2.57 and dash with a clear message.
files("version-gate.sh")
run("""
bash version-gate.sh
!/bin/bash version-gate.sh
!dash version-gate.sh
shellcheck version-gate.sh
""") Output
$ bash version-gate.sh Bash 5.3: new enough $ /bin/bash version-gate.sh This script needs Bash 4 or later; this is 3.2.57(1)-release. [exit status 1] $ dash version-gate.sh This script needs Bash 4 or later; this is not Bash. [exit status 1] $ shellcheck version-gate.sh
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 version_gate_session.py
On Bash 5.3.20 it prints “Bash 5.3: new enough”; on macOS’s Bash 3.2.57 and on dash it prints its message to standard
error and ends with exit status 1 before any later line can misbehave. Under dash the first test already succeeds, so
the || never reaches the array syntax that dash cannot read. ShellCheck 0.11.0 printed nothing about the file, which
means it found no problem.
Key idea
Trust what the running shell says about itself: $BASH_VERSION and BASH_VERSINFO describe the shell that runs the
script, while $SHELL only names your login shell.
A current Bash is one install away on Linux, macOS and Windows
How you get Bash 5.3 depends on the system. Most Linux distributions include Bash and update it through their package
manager, though each release ships its own version, so check with bash --version rather than assuming. On macOS,
/bin/bash stays at 3.2.57; Homebrew’s bash formula is 5.3.20, and Homebrew installs to /opt/homebrew on Apple
silicon. On Windows, Microsoft’s Windows Subsystem for Linux gives you a full Linux, Bash included, after one
wsl --install command in an administrator PowerShell, while Git for Windows includes Git Bash, a Bash emulation built
for running Git from the command line.
| System | How to get Bash 5.3 | How to check |
|---|---|---|
| Linux | The distribution’s package manager | bash --version |
| macOS | brew install bash, then use /opt/homebrew/bin/bash |
type -a bash lists it before /bin/bash |
| Windows | WSL with a Linux distribution, or Git Bash | bash --version inside WSL or Git Bash |
Test with the Bash your readers will use
Run every script you share with the newest Bash you can and with the oldest one your users might have. On a Mac,
that means testing with Homebrew’s Bash and, for anything that must also run there, macOS’s /bin/bash.
Every session in this track was recorded with GNU Bash 5.3.20, built from the official bash-5.3 sources with the patches bash53-001 to bash53-020, so your output will match when your version line says 5.3.20 too.
Checkpoint
Check: Finding the running Bash · Getting Bash 5.3
Practise: name the shell from its output
Each question shows output a shell printed or a situation from a real setup. Decide which shell or version produced it; every wrong answer says what it confuses:
Practice that adapts to you
Practise this lesson
8 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.
Interview questions
Warm-up (fresher to 2–5 years): how does a terminal differ from a shell?
A terminal, today usually a terminal emulator such as Terminal on macOS or Windows Terminal, is the window that draws
text and sends your keystrokes on. A shell such as Bash, zsh or dash is the program inside it that reads each command
line, expands it and starts the programs it names, then waits for them to finish. The two are independent: you can run
any shell in any terminal, and a script runs under a shell with no terminal at all, as cron jobs do. To see which shell
you are in, run echo "$0"; to see its version in Bash, run echo "$BASH_VERSION". $SHELL names your login shell,
which may differ from the one you are using.
Two more questions about versions and portability follow. Answer each one before you open its first step:
Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.
-
Fresher to mid
A script that works on your Linux laptop stops on a colleague's Mac with "declare: -A: invalid option". What is going on, and how do you fix it for both of you?
-
Mid to senior
How would you make a Bash script stop at once, with a clear message, when someone runs it with sh or with a Bash older than version 4?
Flashcards · 5 cards
Recall it, then check
Say the answer to yourself before you look: recalling it is what makes it stick.
-
What is the difference between a terminal emulator and a shell?
The terminal emulator is the window: it draws characters and sends your keystrokes on, and runs no command itself. The shell, such as Bash, zsh or dash, is the program inside it that reads each command line, expands it and starts the programs it names.
-
Why does echo $SHELL not tell you which shell is running a script?
SHELL names your login shell, the one your account starts when you log in. A script can run under a different shell, so ask the running shell itself through BASH_VERSION or BASH_VERSINFO.
-
Which checks tell you which Bash you are running, and which version it is?
In an interactive shell $0 gives the name the shell was started with. BASH_VERSION and the BASH_VERSINFO array describe the running shell, bash --version reports the bash found first on PATH, and type -a bash lists every bash on PATH in search order.
-
Which Bash does macOS keep at /bin/bash, and how do you get a current one?
Bash 3.2.57. Install Bash 5.3 with Homebrew on macOS, with the package manager on Linux, or through WSL or Git Bash on Windows, and then read its version line.
-
Which document defines the sh language, and how do Bash, dash and zsh relate to it?
POSIX.1-2024 defines it. dash implements it closely, Bash implements it and adds many extensions, and zsh, the default login shell of macOS from 10.15, is a separate shell with its own language.
Key takeaways
- A terminal emulator draws text and passes on keystrokes, the shell reads and expands command lines and starts programs, and the programs do the work.
- POSIX.1-2024 defines the
shlanguage; Bash and dash implement it, Bash adds much more, and zsh is the default login shell on macOS from 10.15. $0,$BASH_VERSION,BASH_VERSINFO,bash --versionandtype -a bashtell you which Bash is running, while$SHELLnames only your login shell.- macOS keeps Bash 3.2.57 at
/bin/bash, so install Bash 5.3 with Homebrew, your Linux package manager, WSL or Git Bash, and check the version line.
Terms in this lesson
- login shell
- The shell your account starts when you log in, recorded in the SHELL variable. It need not be the shell that is running a given script.
- shell
- The program that reads command lines, expands them and starts the programs they name, then waits for them to finish. Bash, dash and zsh are shells.
- terminal emulator
- The program that shows a text window, draws the characters programs write and passes your keystrokes on, such as Terminal on macOS or Windows Terminal. It runs no commands itself.
References
- Bash: the GNU Bourne-Again SHell (Chet Ramey (GNU Bash maintainer))
- Bash Reference Manual: Bash Variables (Chet Ramey (GNU Bash maintainer))
- POSIX.1-2024: The Open Group Base Specifications Issue 8 (The Open Group and IEEE)
- dash(1) (man7.org (Linux man-pages))
- Use zsh as the default shell on your Mac (Apple)
- bash formula (Homebrew)
- Homebrew installation (Homebrew)
- How to install Linux on Windows with WSL (Microsoft)
- Git for Windows (Git for Windows)
Report a problem with this lesson
Kept only in this browser. Your Learn progress