Skip to content

Bash Parameter Expansion Cheat Sheet

Transform variable values without spawning a subprocess.

Basic Access

$var          # expand variable
${var}        # explicit boundaries (use when followed by alphanumerics)
${var:-}      # same, but suppresses unbound error from set -u

Defaults and Error Handling

Syntax Meaning
${var:-default} Use default if var is unset or empty
${var-default} Use default only if var is unset (not if empty)
${var:=default} Set var to default if unset or empty, then expand
${var:?message} Error and exit if var is unset or empty
${var:+value} Use value if var IS set (and non-empty)
echo "${NAME:-stranger}"          # "stranger" if NAME unset/empty
: "${CONFIG:=/etc/app.conf}"      # set CONFIG if unset, then continue
: "${REQUIRED:?REQUIRED must be set}"  # exit with error if unset

String Length

${#var}       # length of string
${#arr[@]}    # length of array

Substrings

${var:offset}          # from offset to end (0-indexed)
${var:offset:length}   # from offset, up to length characters
${var: -N}             # last N characters (note the space before -)
str="hello world"
echo "${str:0:5}"    # hello
echo "${str:6}"      # world
echo "${str: -5}"    # world

Prefix Removal

${var#pattern}    # remove shortest matching prefix
${var##pattern}   # remove longest matching prefix (greedy)
file="backup_2024-01-15.tar.gz"
echo "${file#backup_}"    # 2024-01-15.tar.gz
echo "${file##*.}"        # gz
echo "${file##*/}"        # basename (filename from path)

Suffix Removal

${var%pattern}    # remove shortest matching suffix
${var%%pattern}   # remove longest matching suffix (greedy)
file="backup_2024-01-15.tar.gz"
echo "${file%.*}"         # backup_2024-01-15.tar
echo "${file%%.*}"        # backup_2024-01-15
echo "${file%/*}"         # dirname (directory from path)

Find and Replace

${var/pattern/replacement}    # replace first match
${var//pattern/replacement}   # replace all matches
${var/#pattern/replacement}   # replace if at start
${var/%pattern/replacement}   # replace if at end
str="hello hello hello"
echo "${str/hello/world}"    # world hello hello
echo "${str//hello/world}"   # world world world

Case Conversion (bash 4+)

${var,,}    # lowercase all
${var^^}    # uppercase all
${var,}     # lowercase first character
${var^}     # uppercase first character
${var~~}    # toggle case

Indirect Reference

prefix="MY"
varname="${prefix}_VAR"
MY_VAR="hello"
echo "${!varname}"    # hello — expands the variable named in $varname

Quick Reference Table

Expansion Result
${f##*/} basename of path
${f%/*} dirname of path
${f%%.*} filename without any extension
${f##*.} extension only
${f%.*} filename without last extension
${#s} string length
${s:0:3} first 3 characters
${s: -3} last 3 characters
${s,,} lowercase
${s^^} uppercase

Related: variables-quoting