Introduction to Bash
Learn Bash scripting step by step with real output: expansions, quoting, arrays, functions, arguments, strict mode, traps, ShellCheck and bats tests.
Bash is the shell you type commands into on most Linux servers, and the language of countless deployment scripts, CI steps, container entrypoints and cron jobs. It is easy to start with and full of sharp edges: unquoted variables that split into several arguments, set -e that does not stop where you expect, loops that lose their variables in a subshell.
This guide goes deep on Bash itself. Each part explains what Bash really does, shows it with real output, and points out the mistakes that cause bugs in production. Along the way you build logstat, a small command-line tool that summarizes web server logs: a function library in Part 6, a command you can run from anywhere in Part 7, options and validation in Part 8, and tests and CI in Part 10.
What You'll Learn
- What Is Bash? Versions, Startup Files and Your First Script: which Bash you have and why it matters,
shversus Bash, login and interactive shells, the practice files, and what is new in Bash 5.3. - Bash Basics: How Bash Reads and Runs a Command Line: command types, exit codes, the order of expansions, quoting, pipelines, subshells and redirection.
- Working With Files in Bash: glob patterns and
shoptoptions, file names with spaces and dashes, safe loops withfind -print0, reading files and temporary files. - Bash Variables: unset versus empty, parameter expansion, the Bash 5.2
&change, arithmetic traps, indexed and associative arrays,read. - Bash if, case and Loops:
[ ]versus[[ ]], regex matching withBASH_REMATCH,case, loops, and the subshell and stdin traps. - Bash Functions: return values, namerefs,
localand dynamic scope, libraries withsource, and helpers for logging and retries. - How to Make a Bash Script Executable and Run It:
chmod +x, which permissions apply, shebangs,sourceversus running,PATH, cron and the errors you will meet. - Bash Script Arguments:
"$@", validation of numbers, ports and IP addresses,getopts, long options, standard input and exit codes. - Bash Text Processing:
printf, here documents, process substitution,awk,sedandjq, measured speed differences, parallel jobs andcurl. - Bash Best Practices: where
set -euo pipefailfails, traps,flock, ShellCheck, shfmt, bats-core tests, a CI workflow and macOS portability.
Bash Best Practices at a Glance
- Quote every expansion:
"$var","$(cmd)","${array[@]}"(Part 2, Part 4). - Never loop over
lsor$(cat file); use globs andwhile IFS= read -r(Part 3). - Use
[[ ]]and(( ))in Bash scripts, and validate input before arithmetic (Part 5). - Declare variables
localin functions, and return data by printing it (Part 6). - Give every script a Bash shebang and never run it with
sh(Part 1, Part 7). - Build commands in arrays, never in strings for
eval(Part 8). - Use
printf,jqand oneawkcall instead ofecho -e,grepon JSON and per-line loops (Part 9). - Use strict mode, one cleanup trap, ShellCheck and tests (Part 10).
Which Versions This Guide Uses
The guide was updated on 24 October 2026. The terminal output comes from real runs as a normal user (dev) on a machine called devbox:
- Bash 5.2.21 on Ubuntu 24.04.5 LTS for almost everything; Debian 13 (5.2.37) behaves the same.
- Bash 5.3.9 on Ubuntu 26.04.1 LTS for the Bash 5.3 features and messages. Upstream Bash is at 5.3 patch 20.
- Bash 3.2.57, built from the GNU source, for what breaks on macOS, which still ships that version as
/bin/bash. - ShellCheck 0.11.0, shfmt 3.14.1, bats-core 1.14.0 and actionlint 1.7.12, plus Ubuntu 24.04's own
jq,curl,mawkand coreutils.
What is not a real run: the macOS commands in the tabs (BSD sed and date), the ssh, psql, cron and sudo lines, which need other machines or root, and the GitHub Actions workflow, which was checked with actionlint but not run on GitHub. Each of those is shown as code without output.
If you learned Bash from an older tutorial, these are the changes that matter most:
| Old habit | Now | Why |
|---|---|---|
`command` |
$(command) |
Nests without backslashes |
[ "$a" = x -a "$b" = y ] |
[[ $a == x && $b == y ]] |
-a and -o are obsolete and ambiguous |
$[ 1 + 2 ], expr 1 + 2 |
$(( 1 + 2 )) |
$[ ] is deprecated; expr starts a process |
which cmd |
command -v cmd |
A builtin that knows functions and aliases |
echo -e "a\tb" |
printf 'a\tb\n' |
echo differs between shells |
eval "$cmd_string" |
"${cmd[@]}" with an array |
Safe with any argument |
cat file | while read line |
while IFS= read -r line; do ...; done < file |
Keeps variables, spaces and backslashes |
"${s/x/&}" for a literal & |
"${s/x/\&}", or shopt -u patsub_replacement |
& inserts the match since Bash 5.2 |
$RANDOM for anything that should be unpredictable |
$SRANDOM (Bash 5.1+), or better openssl rand for secrets |
$RANDOM is 15 bits from a simple generator |
Prerequisites
- A computer with Linux, macOS or Windows (WSL). Part 1 shows how to get a current Bash on each.
- Basic terminal use. If
cd,ls,cpand pipes are new to you, start with Linux command line basics in the Linux guide, whose shell scripting part is also a gentler first introduction to scripts.
Practice Hands-On
Part 1 creates ~/bash-practice, a small set of log, config and data files that every later part works with, so you can run each example yourself and get the same output. For quick experiments without installing anything, use the Linux Terminal simulator in your browser.
Keep Learning
- What does set -e mean in a Bash script?
- How cat <<EOF works in Bash
- Check if a variable is set in Bash
- Interview questions: Bash scripting basics and shell scripting fundamentals
- The free Introduction to Bash Scripting eBook on GitHub, for another walk through the same topics
- Next guide: Introduction to Git
Start with Part 1: What Is Bash?, or jump to making a script executable if you need that answer now.
We earn commissions when you shop through the links below.
Bitrise
Managed runners for GitHub Actions
Bitrise Build Hub runs your GitHub Actions jobs on M4 Macs and AMD Linux machines. Change runs-on and keep your workflows, secrets and logs on GitHub.
Atomsized
AWS platform engineering and GitOps
Design and automation for reliable AWS and Kubernetes platforms, safer delivery workflows, and preview and UAT environments your engineers can understand and own.
DigitalOcean
Cloud infrastructure for developers
Simple, reliable cloud computing designed for developers
DevDojo
Developer community & tools
Join a community of developers sharing knowledge and tools
SMTPfast
Developer-first email API
Send transactional and marketing email through a clean REST API. Detailed logs, webhooks, and embeddable signup forms in one dashboard.
QuizAPI
Developer-first quiz platform
Build, generate, and embed quizzes with a powerful REST API. AI-powered question generation and live multiplayer.
Want to support DevOps Daily and reach thousands of developers?
Become a SponsorTags
Found an issue?