Home > Articles > Operating Systems, Server > Linux/UNIX/Open Source

  • Print
  • + Share This
This chapter is from the book

Variable Expansion

Variable expansion is the term used for the ability to access and manipulate values of variables and parameters. Basic expansion is done by preceding the variable or parameter name with the $ character. This provides access to the value.

$ UULIB=/usr/lib/uucp 
   $ print $UULIB 
   /usr/lib/uucp 

Other types of expansion can be used to return portions or the length of variables, use default or alternate values, check for mandatory setting, and more.

For the sake of convenience, the term variable will refer to both variables and parameters in the following sections that discuss variable expansion.

$ variable, ${variable}

This is expanded to the value of variable. The braces are used to protect or delimit the variable name from any characters that follow. The next example illustrates why braces are used in variable expansion. The variable CA is set to ca:

$ CA=ca 

What if we wanted to reset CA to california? It could be reset to the entire value, but to make a point, let's try using the current value like this:

$ CA=$CAlifornia 
   $ print $CA 
   
   $ 

Nothing is printed, because without the braces around the variable CA, the Korn shell looks for a variable named $CAlifornia. None is found, so nothing is substituted. With the braces around variable CA, we get the correct value:

$ CA=${CA}lifornia 
   $ print $CA 
   california 

Braces are also needed when attempting to expand positional parameters greater than 9. This ensures that both digits are interpreted as the positional parameter name.

${#variable}

This is expanded to the length of variable. In this example, X is set to a three-character string, so a length of 3 is returned:

$ X=abc 
   $ print ${#X} 
   3 

Whitespace in variable values is also counted as characters. Here the whitespace from the output of the date command is also counted:

$ TODAY=$(date) 
   $ print ${#TODAY} 
   28 

${variable:—word}, ${variableword}

This is expanded to the value of variable if it is set and not null, otherwise word is expanded. This is used to provide a default value if a variable is not set. In the following example, the variable X is set to abc. When expanded using this format, the default value abc is used:

$ X=abc 
   $ print ${X:—cde} 
   abc 

After X is unset, the alternate value cde is used:

$ unset X 
   $ print ${X:—cde} 
   cde 

Notice that the value of X remains unchanged:

$ print $X 
   
   $ 

Let's say we needed a command to get the user name. The problem is that some people have it set to USER, while others have it set to LOGNAME. We could use an if command to check one value first, then the other. This would be quite a few lines of code. Or we could use this form of variable expansion to have both values checked with one command. Here, if USER is set, then its value is displayed, otherwise the value of LOGNAME is displayed.

$ print USER=$USER, LOGNAME=$LOGNAME 
   USER=anatole, LOGNAME=AO 
   $ print ${USER:—${LOGNAME}} 
   anatole 

Now we unset USER to check and make sure that LOGNAME is used:

$ unset USER 
   $ print ${USER:—${LOGNAME}} 
   AO 

But what if both USER and LOGNAME are not set? Another variable could be checked like this:

$ print ${USER:—${LOGNAME:—${OTHERVAR}}} 

But to demonstrate other ways that the alternate value can be expanded, let's just use some text.

$ unset USER LOGNAME 
   $ print ${USER:-${LOGNAME:-USER and LOGNAME \ 
   not set!}} 
   USER and LOGNAME not set! 

In this version, the output of the whoami command is used:

$ print ${USER—${LOGNAME:—$(whoami)}} 
   anatole 

For compatibility with the Bourne shell, it could also be given as:

$ echo ${USER:—${LOGNAME:—`whoami`}} 
   anatole 

Remember that the alternate value is only used and not assigned to anything. The next section shows how you can assign an alternate value if a default value is not set. The other format, ${variable– word}, causes the variable value to be used, even if it is set to null:

$ typeset X= 
   $ print ${X-cde} 
   
   $ 

${variable:= word}, ${variable=word}

This is expanded to the value of variable if set and not null, otherwise it is set to word, then expanded. In contrast to the variable expansion format from the previous section, this format is used to assign a default value if one is not already set. In the next example, the variable LBIN is set to /usr/lbin. When expanded using this format, the default value /usr/lbin is used:

$ LBIN=/usr/lbin 
   $ print ${LBIN:=/usr/local/bin} 
   /usr/lbin 

After LBIN is unset, this form of variable expansion causes LBIN to be assigned the alternate value, /usr/local/bin:

$ unset LBIN 
   $ print ${LBIN:=/usr/local/bin} 
   /usr/local/bin 

Notice that LBIN is now set to /usr/local/bin.

$ print $LBIN 
   /usr/local/bin 

Command substitution can also be used in place of word. This command sets the SYS variable using only one command:

$ unset SYS 
   $ print ${SYS:=$(hostname)} 
   aspd 

The other format, ${variable=word}, causes the variable value to be used, even if it is set to null. Here LBIN is not assigned an alternate value. If := was used instead of =, then LBIN would be set to /usr/local/bin:

$ LBIN= 
   $ print ${LBIN=/usr/local/bin} 
   
   $ 

${variable:?word}, ${variable:?}, ${variable?word}, ${variable?}

This is expanded to the value of variable if it is set and not null, otherwise word is printed and the Korn shell exits. If word is omitted, 'parameter null or not set' is printed. This feature is often used in Korn shell scripts to check if mandatory variables are set. In this example, variable XBIN is first unset. When expanded, the default error is printed:

$ unset XBIN 
   $ : ${XBIN:?} 
   /bin/ksh: XBIN: parameter null or not set 

The ? as the word argument causes the default error message to be used. You could also provide your own error message:

$ print ${XBIN:?Oh my God, XBIN is not set!} 
   /bin/ksh: XBIN: Oh my God, XBIN is not set! 

The other formats, ${variable?word} and ${variable?}, cause the variable value to be used, even if it is set to null.

${variable:+word}, ${variable+word}

This is expanded to the value of word if variable is set and not null, otherwise nothing is substituted. This is basically the opposite of the ${variable:word} format. Instead of using word if variable is not set, word is used if variable is set. In the first example Y is set to abc. When expanded, the alternate value def is displayed because Y is set:

$ Y=abc 
   $ print ${Y:+def} 
   def 

Here, Y is unset. Now when expanded, nothing is displayed:

$ unset Y 
   $ print ${Y:+def} 
   
   $ 

Like the ${variable:word} format, the alternate value is only used and not assigned to the variable. Y is still set to null:

$ print $Y 
   
   $ 

The other format, ${variable+word}, causes the variable value to be used, even if it is set to null:

$ Y= 
   $ print ${Y+def} 
   def 

${variable#pattern}, ${variable##pattern}

This is expanded to the value of variable with the smallest (#) or largest (##) part of the left matched by pattern deleted. What these expansion formats allow you to do is manipulate substrings. To demonstrate the basic functionality, X is set to a string that contains a recurring pattern: abcabcabc.

$ X=abcabcabc 

When expanded to return the substring that deletes the smallest left pattern abc, we get abcabc:

$ print ${X#abc*} 
   abcabc 

while the substring that deletes the largest left pattern abc is abcabcabc, or the entire string:

$ print ${X##abc*} 
   
   $ 

Table 3.5. Variable Expansion Formats

${#variable}

length of variable

${variable:–word}

value of variable if set and not null, else print word

${variable:= word}

value of variable if set and not null, else variable is set to word, then expanded

${variable:+word}

value of word if variable is set and not null, else nothing is substituted

${variable:?}

value of variable if set and not null, else print 'variable: parameter null or not set'

${variable:?word}

value of variable if set and not null, else print value of word and exit

${variable #pattern}

value of variable without the smallest beginning portion that matches pattern

${variable ##pattern}

value of variable without the largest beginning portion that matches pattern

${variable%pattern}

value of variable without the smallest ending portion that matches pattern

${variable%%pattern}

value of variable without the largest ending portion that matches pattern

${variable//pattern1/pattern2}

replace all occurrences of pattern1 with pattern2 in variable

We could use this concept to implement the Korn shell version of the Unix basename command. The pattern in this command causes the last directory to be returned if variable X is set to a full pathname:

$ X=/usr/spool/cron 
   $ print ${X##*/} 
   cron 

${variable%pattern}, ${variable%%pattern}

This is expanded to the value of variable with the smallest (%) or largest (%%) part of the right matched by pattern deleted. This is the same as the parameter expansion format from the previous section, except that patterns are matched from the right instead of left side. It could also be used to display file names without their .suffixes:

$ X=file.Z 
   $ print ${X%.*} 
   file 

Here, any trailing digits are stripped:

$ X=chap1 
   $ print ${X%%[0—9]*} 
   chap 
   $ X=chap999 
   $ print ${X%%[0—9]*} 
   chap 

The pattern in this command causes it to act like the Unix dirname command. Everything except the last directory is returned if variable X is set to a full pathname.

$ X=/usr/spool/cron 
   $ print ${X%/*} 
   /usr/spool 

${variable//pattern1/pattern2}, ${variable/pattern1/pattern2}, ${variable#pattern1/pattern2}, ${variable/%pattern1/pattern2}

The Korn shell supports four search and replace operations on variables. This example changes all occurrences of abc in X to xyz:

$ X=abcabcabc 
   $ print ${X//abc/xyz} 
   xyzxyzxyz 

while this one only changes the first occurrence of abc in X to xyz:

$ X=abcabcabc 
   $ print ${X/abc/xyz} 
   xyzabcabc 

See Table 3.6 for detailed explanation of the other formats.

${variable:start}, ${variable:start:length}

This format returns a substring. The first returns variable from position start to end, while the second returns length characters from variable from character position start to end. For example, this returns the first 3 characters of X:

$ X=abcdefghij 
   $ print {$X:0:3} 
   abc 

while this example returns the value of X starting at character position 5:

$ X=abcdefghij 
   $ print {$X:5} 
   fghij 
  • + Share This
  • 🔖 Save To Your Account