Bourne Shell Scripting/Variable Expansion

From Wikibooks, open books for an open world
Jump to: navigation, search

In the Environment module we introduced the idea of an environment variable as a general way of storing small pieces of data. In this module we take an in-depth look at using those variables: 'variable expansion', 'parameter substitution' or just 'substitution'.

Substitution[edit]

The reason that using a variable is called substitution is that the shell literally replaces each reference to any variable with its value. This is done while evaluating the command-line, which means that the variable substitution is made before the command is actually executed.

The simplest way of using a variable is the way we've already seen, prepending the variable name with a '$'. So for instance:

Simple use of a variable

Crystal Clear app terminal.png Code:

$ USER=JoeSixpack
$ echo $USER

Crystal Clear app kscreensaver.png Output:

JoeSixpack
The value JoeSixpack is substituted for $USER before the echo command is executed.

Of course, once the substitution is made the result is still just the text that was in the variable. The interpretation of that text is still done by whatever program is run. So for example:

Variables do not make magic

Crystal Clear app terminal.png Code:

$ USER=JoeSixpack
$ ls $USER

Crystal Clear app kscreensaver.png Output:

ls: cannot access JoeSixpack: No such file or directory
Just because the text came from a variable, doesn't mean the file exists.

Basic variable expansion is already quite flexible. You can use it as described above, but you can also use variables to create longer strings. For instance, if you want to set the log directory for an application to the "log" directory in your home directory, you might fill in the setting like this:

$HOME/log

And if you're going to use that setting more often, you might want to create your own variable like this:

LOGDIR=$HOME/log

And, of course, if you want specific subdirectories for logs for different programs, then the logs for the Wyxliz application go into directory

$LOGDIR/Wyxliz/

Substitution forms[edit]

The Bourne Shell has a number of different syntaxes for variable substitution, each with its own meaning and use. In this section we examine these syntaxes.

Basic variable substitution[edit]

We've already talked at length about basic variable substitution: you define a variable, stick a '$' in front of it, the shell substitutes the value for the variable. By now you're probably bored of hearing about it.

But we've not talked about one situation that you might run into with basic variable substitution. Consider the following:

Adding some text to a variable's value

Crystal Clear app terminal.png Code:

$ ANIMAL=duck
$ echo One $ANIMAL, two $ANIMALs

Crystal Clear app kscreensaver.png Output:

One duck, two
Uhhh.... we're missing something...

So what went wrong here? Well, obviously the shell substituted nothing for the ANIMAL variable, but why? Because with the extra 's' the shell thought we were asking for the non-existent ANIMALs variable. But what gives there? We've used variables in the middle of strings before (as in '/home/ANIMAL/logs'). But an 's' is not a '/': an 's' can be a valid part of a variable name, so the shell cannot tell the difference. In cases where you explicitly have to separate the variable from other text, you can use braces:

Adding some text to a variable's value, take II

Crystal Clear app terminal.png Code:

$ ANIMAL=duck
$ echo One $ANIMAL, two ${ANIMAL}s

Crystal Clear app kscreensaver.png Output:

One duck, two ducks
That's better!

Both cases (with and without the braces) count as basic variable substitution and the rules are exactly the same. Just remember not to leave any spaces between the braces and the variable name.

Substitution with a default value[edit]

Since a variable can be empty, you'll often write code in your scripts to check that mandatory variables actually have a value. But in the case of optional variables it is usually more convenient not to check, but to use a default value for the case that a variable is not defined. This case is actually so common that the Bourne Shell defines a special syntax for it: the dash. Since a dash can mean other things to the shell as well, you have to combine it with braces — the final result looks like this:

${varname[:]-default}

*Where varname is the name of the variable

and default is the value used if varname is not defined

Again, don't leave any spaces between the braces and the rest of the text. The way to use this syntax is as follows:

Default values

Crystal Clear app terminal.png Code:

$ THIS_ONE_SET=Hello
$ echo $THIS_ONE_SET ${THIS_ONE_NOT:-World}

Crystal Clear app kscreensaver.png Output:

Hello World

Compare that to this:

Default not needed

Crystal Clear app terminal.png Code:

$ TEXT=aaaaaahhhhhhhh
$ echo Say ${TEXT:-bbbbbbbbbb}

Crystal Clear app kscreensaver.png Output:

Say aaaaaahhhhhhhh

Interestingly, the colon is optional; so ${VAR:-default} has the same result as ${VAR-default}.

Substitution with default assignment[edit]

As an extension to default values, there's a syntax that not only supplies a default value but assigns it to the unset variable at the same time. It looks like this:

${varname[:]=default}

*Where varname is the name of the variable

and default is the value used and assigned if varname is not defined

As usual, avoid spaces in between the braces. Here's an example that demonstrates how this syntax works:

Default value assignment
$ echo $NEWVAR
 
$ echo ${NEWVAR:=newval}
newval
$ echo $NEWVAR
newval


As with the default value syntax, the colon is optional.

Substitution for actual value[edit]

This substitution is sort of a quick test to see if a variable is defined (and that's usually what it's used for). It's sort of the reverse of the default value syntax and looks like this:

${varname[:]+substitute}

*Where varname is the name of the variable

and substitute is the value used if varname is defined

This syntax returns the substitute value if the variable is defined. That sounds counterintuitive at first, especially if you ask what is returned if the variable is not defined — and learn that the value is nothing. Here's an example:

Actual value substitution
$ echo ${NEWVAR:+newval}
 
$ NEWVAR=oldval
$ echo ${NEWVAR:+newval}
newval


So what could possibly be the use of this notation? Well, it's used often in scripts that have to check whether lots of variables are set or not. In this case the fact that a variable has a value means that a certain option has been activated, so you're interested in knowing that the variable has a value, not what that value is. It looks sort of like this (pseudocode, this won't actually work in the shell):

Default value assignment
if ${SPECIFIC_OPTION_VAR:+optionset} == optionset then ...


Of course, in this notation the colon is optional as well.

Substitution with value check[edit]

This final syntax is sort of a debug check to check whether or not a variable is set. It looks like this:

${varname[:]?message}

*Where varname is the name of the variable

and message is the printed if varname is not defined

With this syntax, if the variable is defined everything is okay. Otherwise, the message is printed and the command or script exits with a non-zero exit status. Or, if there is no message, the text "parameter null or not set" is printed. As usual the colon is optional and you may not have a space between the colon and the variable name.

You can use this syntax to check that the mandatory variables for your scripts have been set and to print an error message if they are not.

Default value assignment
$ echo ${SOMEVAR:?has not been set}
-sh: SOMEVAR: has not been set
$ echo ${SOMEVAR:?}
-sh: SOMEVAR: parameter null or not set


Next Page: Control flow | Previous Page: Environment

Home: Bourne Shell Scripting