Useful Bash Parameter Expansion Patterns
Reference for the high-value forms of {{Bash parameter expansion}}: default values, length, prefix/suffix stripping (greedy and non-greedy), pattern substitution, substring slicing, and case modification. The ${var...} syntax that nobody remembers cold but everyone Googles.
Bash parameter expansion is the family of ${...} forms that transform a variable as it expands, without spawning sed, awk, or cut. Most people memorize three or four shapes and look up the rest each time. The full grammar lives in the Bash (Shell) manual chapter on parameter expansion. **Defaults and assertions.** ${var:-default} expands to default when var is unset or empty, leaving var untouched. ${var:=default} does the same but also assigns default back to var. ${var:?error message} aborts the script (or interactive shell line) and prints the error message to stderr if var is unset or empty, which is a one-liner way to assert required environment variables. ${var:+alt} is the mirror image: it expands to alt only when var is set. The colon makes all four forms treat an empty string the same as unset; drop the colon to distinguish empty-but-set from unset. **Length.** ${#var} returns the character length of the value, and ${#array[@]} returns the number of elements in an array. **Prefix and suffix removal.** ${var#pattern} deletes the shortest match of pattern at the start of var; ${var##pattern} deletes the longest match. ${var%pattern} and ${var%%pattern} do the same at the end. The pattern is a shell glob, not a regular expression. The canonical idiom is ${file##*.} to extract a file extension (strip everything up to and including the last dot) and ${path##*/} to implement basename. Symmetrically, ${path%/*} gives dirname. **Substitution.** ${var/pattern/replacement} replaces the first match of pattern with replacement; ${var//pattern/replacement} replaces every match. Anchored forms ${var/#pattern/...} and ${var/%pattern/...} match only at the start or end. Omitting the replacement deletes matches outright. **Substring.** ${var:offset} returns the value starting at the given zero-indexed character. ${var:offset:length} also bounds the length. Negative offsets count from the end but require a space or parentheses to avoid colliding with the ${var:-default} syntax: ${var: -3} or ${var:(-3)}. **Case modification (Bash 4+).** ${var^^} uppercases the whole value, ${var,,} lowercases it, ${var^} and ${var,} touch only the first character, and an optional pattern after each form restricts which characters are affected. Real-world uses are mostly defensive: PORT=${PORT:-8080} to provide a sane default, : ${DATABASE_URL:?must be set} as an early-fail guard, ext=${file##*.} for extension dispatch, and ${path%/*}/ to derive a directory from a full path without forking dirname. Because these are pure shell builtins, they also work in the more constrained POSIX Shell subset of the syntax (the basic four — :-, :=, :?, :+ — are POSIX; the substitution, case, and substring forms are Bash extensions).