# 10.3. Operations on variables

## 10.3.1. Arithmetic on variables

We discussed this already in Section 3.4.6.

## 10.3.2. Length of a variable

Using the \${#VAR} syntax will calculate the number of characters in a variable. If VAR is "*" or "@", this value is substituted with the number of positional parameters or number of elements in an array in general. This is demonstrated in the example below:

 ``` [bob in ~] echo \$SHELL /bin/bash [bob in ~] echo \${#SHELL} 9 [bob in ~] ARRAY=(one two three) [bob in ~] echo \${#ARRAY} 3 ```

## 10.3.3. Transformations of variables

### 10.3.3.1. Substitution

\${VAR:-WORD}

If VAR is not defined or null, the expansion of WORD is substituted; otherwise the value of VAR is substituted:

 ``` [bob in ~] echo \${TEST:-test} test [bob in ~] echo \$TEST [bob in ~] export TEST=a_string [bob in ~] echo \${TEST:-test} a_string [bob in ~] echo \${TEST2:-\$TEST} a_string ```

This form is often used in conditional tests, for instance in this one:

 ``` [ -z "\${COLUMNS:-}" ] && COLUMNS=80 ```

It is a shorter notation for

 ``` if [ -z "\${COLUMNS:-}" ]; then COLUMNS=80 fi ```

If the hyphen (-) is replaced with the equal sign (=), the value is assigned to the parameter if it does not exist:

 ``` [bob in ~] echo \$TEST2 [bob in ~] echo \${TEST2:=\$TEST} a_string [bob in ~] echo \$TEST2 a_string ```

The following syntax tests the existence of a variable. If it is not set, the expansion of WORD is printed to standard out and non-interactive shells quit. A demonstration:

 ``` [bob in ~] cat vartest.sh #!/bin/bash # This script tests whether a variable is set. If not, # it exits printing a message. echo \${TESTVAR:?"There's so much I still wanted to do..."} echo "TESTVAR is set, we can proceed." [bob in testdir] ./vartest.sh ./vartest.sh: line 6: TESTVAR: There's so much I still wanted to do... [bob in testdir] export TESTVAR=present [bob in testdir] ./vartest.sh present TESTVAR is set, we can proceed. ```

Using "+" instead of the exclamation mark sets the variable to the expansion of WORD; if it does not exist, nothing happens.

### 10.3.3.2. Removing substrings

To strip a number of characters, equal to OFFSET, from a variable, use this syntax:

\${VAR:OFFSET:LENGTH}

The LENGTH parameter defines how many characters to keep, starting from the first character after the offset point. If LENGTH is omitted, the remainder of the variable content is taken:

 ``` [bob in ~] export STRING="thisisaverylongname" [bob in ~] echo \${STRING:4} isaverylongname [bob in ~] echo \${STRING:6:5} avery ```

\${VAR#WORD}

and

\${VAR##WORD}

These constructs are used for deleting the pattern matching the expansion of WORD in VAR. WORD is expanded to produce a pattern just as in file name expansion. If the pattern matches the beginning of the expanded value of VAR, then the result of the expansion is the expanded value of VAR with the shortest matching pattern ("#") or the longest matching pattern (indicated with "##").

If VAR is * or @, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list.

If VAR is an array variable subscribed with "*" or "@", the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list. This is shown in the examples below:

 ``` [bob in ~] echo \${ARRAY[*]} one two one three one four [bob in ~] echo \${ARRAY[*]#one} two three four [bob in ~] echo \${ARRAY[*]#t} one wo one hree one four [bob in ~] echo \${ARRAY[*]#t*} one wo one hree one four [bob in ~] echo \${ARRAY[*]##t*} one one one four ```

The opposite effect is obtained using "%" and "%%", as in this example below. WORD should match a trailing portion of string:

 ``` [bob in ~] echo \$STRING thisisaverylongname [bob in ~] echo \${STRING%name} thisisaverylong ```

### 10.3.3.3. Replacing parts of variable names

This is done using the

\${VAR/PATTERN/STRING}

or

\${VAR//PATTERN/STRING}

syntax. The first form replaces only the first match, the second replaces all matches of PATTERN with STRING:

 ``` [bob in ~] echo \${STRING/name/string} thisisaverylongstring ```