Skip to content

Shell string expansion

September 29, 2023
December 8, 2014

Parameter Expansion

Parameter Expansion - Bash Reference Manual
Parameter Substitution

bash assign default value - Stack Overflow

bash - nested double quotes in assignment with command substitution - Unix & Linux Stack Exchange $() resets double quotes ""

${parameter-default}, ${parameter:-default}
The extra : makes a difference only when parameter has been declared, but is null.

unset EGGS
echo 1 ${EGGS-spam}   # 1 spam
echo 2 ${EGGS:-spam}  # 2 spam

EGGS=
echo 3 ${EGGS-spam}   # 3
echo 4 ${EGGS:-spam}  # 4 spam

EGGS=cheese
echo 5 ${EGGS-spam}   # 5 cheese
echo 6 ${EGGS:-spam}  # 6 cheese

string manipulation/expansion

After reading fish shell's philosophy, I now think using sed and other tools is better than relying on shell features.

Manipulating Strings
Parameter expansion [Bash Hackers Wiki]
Bash string processing
Bash One-Liners Explained, Part II: Working with strings - good coders code, great coders reuse

TODO: add zsh manual

# to upper
echo $string | tr [:lower:] [:upper:]
newstring=${string^^}
# to lower
echo $string | tr [:upper:] [:lower:]
newstring=${string,,}

# substring extraction
substring=${string:1:-2}

# string expansion
${var:-default} # means $var if $var is defined and otherwise "default"
${var:-} # default $var to null string to avoid error when `set -u` is used
${var:+value} # means if $var is defined use "value"; otherwise nothing

# string substitution
${string/substring/replacement}   # replace "substring" with "replacement"
${string//substring/replacement}  # replace all occurrences (g) of "substring" with "replacement"
${string/#substring/replacement}  # replace front match (^) "substring" with "replacement"
${string/%substring/replacement}  # replace end match ($) "substring" with "replacement"

# file path manipulation
# get dir from full path
$(dirname "$path")
${path%/*}
# get file name from full path
$(basename "$path")
${path##*/}

FILE="example.tar.gz"
${FILE%%.*}          # "example", stripped longest extension
${FILE%.*}           # "example.tar", stripped shortest extension
${FILE#*.}           # "tar.gz", longest extension
${FILE##*.}          # "gz", shortest extension

# mimic https://nodejs.org/api/path.html#path_path_parse_pathstring
declare -A pathObj
base=${file##*/}
pathObj[dir]=${file%/*}
pathObj[base]=${base}
pathObj[name]=${base%.*}
pathObj[ext]=.${base##*.} # note added '.' prefix
# NOTE: ext has bug if $file has no extension

if [ ${path:0:1} = '/' ]; then
    tmp=${path:1}    # strip leading '/'
fi
tmp=${path#/}        # strip leading '/'
tmp=${path%/}        # strip trailing '/'