9. Shell Parameter Expansion

Parameter expansion allows the substitution of parameter names by their values. Parameter names put between the "${...}" operator will expanded:

$ word="Orange"
$ echo ${word}
Orange

as well as parameter names prefixed by the "$" operator:

$ echo $word 
Orange

Before the value is substituted it can be transformed by a large set of operations. By using the ":-" operator a undefined variable can be replace by a value (default):

$ unset integer
$ echo ${integer:-0}
0

or a null value of a declared variable:

$ integer=
$ echo ${integer:-0}
0

To initialize an undeclared variable before substitution the ":=" operator is used:

$ unset integer
$ echo ${integer:=1}
1

To write a message about a null value or an undeclared variable to stderr the "?" operator is used:

$ unset verse
$ echo ${verse:?"Oranges and lemons say the bells of St. Clement's"}
bash: verse: Oranges and lemons say the bells of St. Clement's

To expand a sub string from a value the ":offset:length" operator is used. :

$ string="/home/pa/bin"
$ echo ${string:6:2}
pa

Offset is the offset taken before sub string, length its length. Without length the offset is removed:

$ echo ${string:6}
pa/bin

Beware of the order of expansions:

$ ls "~${string:6:2}/bin"
ls: cannot access ~pa/bin: No such file or directory

Tilde expansion is done before parameter expansion. Hence "${string:6:2}" is taken literal as login name. Because of this user dosen't exists "~" is left unchanged by tilde expansion. But the literal path "~pa/bin" doesn't exist. Sub arrays can be expanded using subscripts "@" or "*" too:

$ fruits=(orange lemon apple melone banana)
$ echo ${fruits[@]:2,2}
apple melone

Offset is index of the first element within the expanded sub array, length its length. Each value of an array element is expanded to a proper word using the subscripts "@" or "*":

$ echo ${fruits[@]}
orange lemon kiwi banana

The number of array elements can be expanded using the "#" operator:

$ echo ${#fruits[@]}
4

Within double quotes subscript "@" still expands each value to a word:

$ words=("${fruits[@]}");
$ echo ${#words[@]}
4

but "*" expands all array elements to a single word separated by the first character of the IFS (Input Field Separators) variable:

$ word=("${fruits[*]}");
$ echo ${#word[*]}
1

To expand the indexes of any array indirect expansion by the "!" operator is used:

echo ${!fruits[@]}
0 1 2 3

The length of a value can be expanded by the "#" also:

$ verse="Oranges and lemons say the bells of St. Clement's"
$ echo ${#verse}
50

To expand the number of positional parameters:

$ echo ${#@}
0

To expand all variable names starting with a prefix into a single word, separated by the first character of the IFS variable, indirect expansion "!" in conjunction with subscript "@" is used:

$ declare vertext=2
$ echo ${!ve@}
verse vertex

"@" masks the remaining characters of the names. To remove the longest match of a pattern, as described in section filename expansion, from the beginning of a value, the "##pattern" operator is use:

$ path="archive.tar.gz"
$ echo ${path##*.}
gz

To remove the shortest match of a pattern from the beginning of a value, the "#pattern" operator is used:

$ echo ${path#*.}
tar.gz

To remove the longest match of a pattern from the end of a value the, "%pattern" operator is used:

$ echo ${path%%.*}
archive

To remove the shortest match of a pattern from the end of a value "%pattern" operator is used:

$ echo ${path%*.*}
archive.tar

To replace the first of the longest matches of a pattern in a value by a string, the "/pattern/string" operator is used:

$ echo ${path/./:}
archive:tar.gz

To replace all matches, the "//pattern/string" operator is used:

$ echo ${path//./:}
archive:tar:gz

To remove the match from the value, the "/pattern" operator is used:

$ echo ${path//.ar}
chive.t.gz

The transformations from above can be done even to all positional parameters:

$ echo ${@//./:}

as well as on all array elements:

$ echo ${fruits[@]//a*/A}
orA lemon A melone bA

A certain character in an variable, any array element or any positional parameters can be brought to upper case by the "^^character" operator:

$ echo ${fruits[@]^^n}
oraNge lemoN apple meloNe baNaNa

or to lower case by the ",,character" operator:

$ echo ${verse,,C}
Oranges and lemons say the bells of St. clements

Parameter expansion is not nestable, but indirect expansion can be used:

$ ref="verse"
$ echo ${!ref}
Oranges and lemons say the bells of St. Clement's.

The value of ref is treated as name of the variable to be expanded.