replace()

${parameter/old/new} - replace one occurrence

${parameter//old/new} - replace all occurrences

~ ✘  f=asdf.txt
~ ✘  echo ${f/txt/md}
asdf.md

Substring removal using pattern matching

Remove from anywhere

${parameter/pattern}

~ ✘  f=asdf.log.gz
~ ✘  echo ${f/.log}
asdf.gz

Remove from the right; suffix

${parameter%word} - shortest match

${parameter%%word} - longest match

~ ✘  f=asdf.log.gz
~ ✘  echo ${f%.*}
asdf.log
~ ✘  echo ${f%%.*}
asdf

Remove from the left; prefix

${parameter#word} - shortest match

${parameter##word} - longest match

~ ✘  f=asdf.log.gz
~ ✘  echo ${f#*.}
log.gz
~ ✘  echo ${f##*.}
gz

len()

${#parameter}

~ ✘  f=asdf
~ ✘  echo ${#f}
4

Set default value for a parameter

${parameter:=default}

Not to be confused with :-.

:= sets the value of $parameter going forward.

:- leaves $parameter unset.

~ ✘  echo $f

~ ✘  echo ${f:=asdf}
asdf
~ ✘  echo "f=$f"
f=asdf

vs

~ ✘  echo $f

~ ✘  echo ${f:-asdf}
asdf
~ ✘  echo "f=$f"
f=

Throw error on empty parameter

${parameter:?error_message}

~ ✘  echo $f

~ ✘  echo ${f:?is undefined}
-bash: f: is undefined
~ ✘  echo $?
1

Override a parameter

${parameter:+override}

This is the opposite of :-. If $parameter is empty, do nothing, else substitute override

~ ✘  f=asdf
~ ✘  echo $f
asdf
~ ✘  echo ${f:+not asdf}
not asdf
~ ✘  unset f
~ ✘  echo ${f:+not asdf}

Substring manipulation; slice()

${parameter:offset:length}

Remove starting from the left

${parameter:offset}

~ ✘  f=asdf.log.gz
~ ✘  echo ${f:3}
f.log.gz

Remove starting from the right

${parameter::len()-length}

~ ✘  f=asdf.log.gz
~ ✘  echo ${f::${#f}-3}
asdf.log

Keep starting from the left

${parameter::length}

~ ✘  f=asdf.log.gz
~ ✘  echo ${f::3}
asd

Keep starting from the right

${parameter: negative_offset:length}

To not collide with :- there must be a space between : and the negative number.

~ ✘  f=asdf.log.gz
~ ✘  echo ${f: -3}
.gz

Extract from anywhere

${parameter:offset:length}

~ ✘  f=asdf.log.gz
~ ✘  echo ${f:5:3}
log

Sources: