Skip to content

Chapter 2 of 8

Variables, Expansion, Quoting, and Strict Mode

A Bash variable is a named storage location for a value. Variables are assigned with NAME=value — critically, with no spaces around the = sign, because Bash treats VAR = value as a command named VAR with two arguments = and value. Values are referenced as \(NAME or, more explicitly and safely, as \){NAME}. The braced form disambiguates boundaries: \({VAR}suffix correctly means the value of VAR concatenated with a literal suffix, while the unbraced \)VARsuffix is interpreted as a single (and probably non-existent) variable. Without export, a variable is local to the current shell; to make it visible to child processes, use export VAR=value or the two-step VAR=value; export VAR. The declare builtin provides additional type hints: declare -i forces arithmetic on assignment, while declare -r makes a variable read-only and equivalent to readonly.

Bash provides a rich family of parameter expansions that operate on the value of a variable without spawning external commands. \({VAR:-default} substitutes default when VAR is unset or empty, while \){VAR:=default} also assigns the default back to VAR. For required configuration, \({VAR:?message} prints the message to stderr and aborts with status 1 if VAR is unset or empty. Length is queried with \){#var}, substrings with \({var:offset:length} (negative offsets count from the end), and patterns can be removed or replaced: \){var#pattern} strips the shortest prefix, \({var##pattern} the longest, \){var%suffix} the shortest suffix, and \({var%%suffix} the longest. Substitution uses \){var/old/new} (first match), \({var//old/new} (all), \){var/#old/new} (anchored at the start), and \({var/%old/new} (anchored at the end). Bash 4 adds case conversion with \){var^^} (upper) and \({var,,} (lower), with the single-character variants \){var^} and ${var,} capitalizing or decapitalizing the first character.

Quoting is the single most important defensive habit in Bash. Single quotes preserve every character literally, while double quotes preserve everything except \(, backticks, and \. Always double-quote variable expansions ("\)var") to prevent word splitting and globbing, because after unquoted parameter, command, and arithmetic expansions Bash splits the result into words on each character of IFS. The default IFS is space, tab, and newline; many scripts override it to IFS=$'\n\t' to avoid word-splitting surprises on whitespace in filenames. Globbing is the matching of unquoted *, ?, and [...] against filenames; it can be disabled with set -f, and the often-surprising behaviour of empty globs can be changed with shopt -s nullglob (expand to nothing) or shopt -s failglob (treat as an error). Other useful shopt flags include nocaseglob for case-insensitive matching, dotglob for including hidden files, and globstar to enable ** for recursive matching.

For robust scripts, a recommended preamble is set -euo pipefail. set -e causes the shell to exit immediately on any command that returns non-zero, except in contexts where the status is explicitly tested (such as if, while, ||, or &&). set -u treats unset variables as errors when expanded, catching typos and missing configuration. set -o pipefail makes a pipeline's exit status reflect the rightmost command to fail, instead of only the last command's status. The special variable $? holds the exit status of the most recent command (zero is success; non-zero is failure), and Bash reserves several standard codes: 1 for general error, 2 for misuse of a shell builtin, 126 for a command found but not executable, 127 for command not found, and 128 + N for termination by signal N (so 130 is SIGINT, 137 is SIGKILL, and 143 is SIGTERM). For output, prefer printf '%s\n' "$var" over echo, which adds a trailing newline and may interpret backslash escapes inconsistently across shells, and direct error messages to stderr with printf '%s\n' "error" >&2.

All chapters
  1. 1Foundations of Bash Scripting
  2. 2Variables, Expansion, Quoting, and Strict Mode
  3. 3Conditionals and Tests
  4. 4Loops and Iteration
  5. 5Functions, Sourcing, and Command-Line Arguments
  6. 6Arrays, Strings, Substitutions, and Arithmetic
  7. 7Input/Output, Redirection, and File Handling
  8. 8Process Control, Scheduling, and Robust Practices

Drill it

Reading is not remembering. These come from the Bash Scripting For Automation deck:

Q

What is Bash?

Bash (Bourne Again SHell) is a Unix shell and command language written as a free software replacement for the Bourne shell (sh). It is the default login shell o...

Q

What file extension is conventionally used for Bash scripts?

.sh. While not strictly required for execution, .sh signals intent and lets tooling treat the file as a shell script.

Q

What must the first line of an executable Bash script be?

A shebang line, e.g. #!/usr/bin/env bash or #!/bin/bash, which tells the kernel which interpreter to invoke.

Q

What command makes a script file executable?

chmod +x script.sh (or chmod 755 script.sh).