## 3. Operations on variables

### 3.1. Arithmetic on variables

We discussed this already in Section 4.6, “Arithmetic expansion”.

### 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
```

### 3.3. Transformations of variables

#### 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.

#### 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
```

#### 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
```