These expansions replace many calls to sed, basename and dirname and make scripts faster and shorter.
${...} can do much more than read a variable. The forms you will use constantly:
- Defaults:
${var:-def}givesdefif var is unset or empty;${var:=def}also assigns it;${var:?message}aborts the script with the message;${var:+alt}givesaltonly when var is set. - Remove a prefix/suffix pattern:
#removes the shortest matching prefix,##the longest;%and%%do the same at the end. So${path##*/}is the base name and${path%/*}the directory,${file%.*}drops the extension. - Replace:
${var/old/new}first match,${var//old/new}all matches; patterns are globs, not regexes. - Length and substrings:
${#var}and${var:offset:length}; negative offsets need a space:${var: -3}. - Case (bash 4+):
${var^}capitalizes the first letter,${var^^}upper-cases all,${var,,}lower-cases.
Without the colon (${var-def}) the default applies only when var is unset, not when it is empty. That distinction matters for optional settings where an empty value is meaningful.
These expansions run inside the shell, so they are much faster in loops than spawning basename or sed for every item.
Example
path="/var/log/nginx/access.log.gz"
echo "${path##*/}" # access.log.gz (basename)
echo "${path%/*}" # /var/log/nginx (dirname)
echo "${path%.gz}" # /var/log/nginx/access.log
echo "${path#*.}" # log.gz (up to the first dot)
echo "${#path}" # 28
echo "${path/log/LOG}" # /var/LOG/nginx/access.log.gz
echo "${path//log/LOG}" # /var/LOG/nginx/access.LOG.gz
echo "${path:5:3}" # log
echo "${path: -2}" # gz
unset port
echo "${port:-8080}" # 8080 (port is still unset)
echo "${port:=3000} $port" # 3000 3000
name=ada
echo "${name^} ${name^^}" # Ada ADA
# : "${API_KEY:?must be set}" -> aborts: API_KEY: must be setRemember
- ${v:-def} default, ${v:=def} assign, ${v:?msg} require
- # and ## strip prefixes, % and %% strip suffixes
- ${v//a/b} replaces with glob patterns; ${#v} is the length
Watch out for
- Writing ${var:-3} when you meant the last 3 characters: you need ${var: -3} with a space.