Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Variables, Expansion, and Quoting

In both the Bourne shell and the C shell, lines of code are processed in multiple passes. The first pass is a parsing pass in which the basic structure of the line of code is extracted. In this pass, quotation marks serve as delimiters between individual pieces of information. For example, you can print a letter immediately after the contents of a variable without a space by closing (and reopening if necessary) the enclosing double quotes immediately after the variable name.

The second pass is an expansion pass. In this pass, any variable is expanded and any inline execution is performed. If a variable contains special characters, the resulting text is further expanded unless that variable is surrounded by double quotes. This may cause unexpected behavior if, for example, a variable contains a wildcard character.

Note: While the expansion of a variable or command inline will not cause a syntax error by itself, it can change the behavior of the eval command. See “Data Structures, Arrays, and Indirection” for more information.

Finally, the third pass is an execution pass. In this pass, the code is actually executed.

In some cases, you may need to change the way variable expansion takes place. You might want to use a nonstandard character to split a variable containing a list, change the way the shell handles special characters, or execute a command and substitute its output in the middle of another command. These techniques are described in the sections that follow.

In this section:

Variable Expansion and Field Separators
Special Characters Explained
Quoting Special Characters
Inline Execution


Variable Expansion and Field Separators

In Bourne shell scripts, two operations are affected by the value of the IFS (internal field separators) shell variable: the read statement and variable expansion. The effect on the read statement is described separately in “Shell Variables and Printing.” In C shell scripts, only variable expansion is affected.

Whenever the shell expands a variable, the value of IFS comes into play. For example, the following script will print “a” and “b” on separate lines, then “c d” on a third line:

#!/bin/sh
 
IFS=":"
LIST="a:b:c d"
for i in $LIST ; do
        echo $i
done

This occurs only because the value on the right side of the for statement contains a variable (LIST) that is expanded by the shell. When the shell expands the variable, it replaces the colon with a space and quotes any spaces in the original string. In effect, by the time the for statement sees the values, the right side of the for statement contains a b c\ d, just as in the example shown in “The for Statement.”

If you insert the exact contents of LIST on the right side of the variable, this script will instead print “a:b:c” on one line and “d” on the other. This is why it is very important to choose record separators correctly.

Cross-Platform Compatibility Note: This treatment of record separators is specific to BASH. Some Bourne shell variants use IFS when the shell splits a list even if no expansion is involved.

To avoid unexpected behavior, you should avoid setting nonstandard values for IFS except when you are expanding a shell variable that depends on this.

As an exception, it is safe to modify IFS during a read statement. Be sure to save the original value in another variable and restore it afterwards, however, to avoid unexpected behavior elsewhere in the script.

Special Characters Explained

There are eight special characters in shell scripts: an asterisk (*), a question mark (?), curly braces ({ and }), square brackets ([ and ]) and single- and double-quote marks (‘ and “). You can use them as follows:

If your script accepts user input, these characters can produce unexpected results if you do not quote them properly. Consider the following example:

#!/bin/sh
echo "Filename?"
read NAME
ls $NAME
ls "$NAME"

If a user types *.jpg at the prompt, the first command lists all files ending in .jpg because the variable is expanded first, and then the expression within it is expanded. The second command lists a single file (or prints an error if you don’t have a file named *.jpg).

Quoting Special Characters

Sometimes, when writing shell scripts, you may need to explicitly include quotation marks, dollar signs, or other special characters in your output. The way that you do this depends on the context.

If the character you wish to quote is not within quote marks, you probably should be. Otherwise, you have to deal with all of the shell special characters (described in “Special Characters Explained”) plus any new special characters that might be added in the future. This is particularly important if your script takes arbitrary user input and passes it as an argument.

However, if your script is not handling user input, you can quote a character by simply preceding it with a backslash (\). This tells the shell to treat it as a literal character instead of interpreting it normally. For example, the following code sample prints the word “Hello” enclosed in double-quotation marks.

echo \"Hello\"

If the character you wish to quote is within double quotes, the same rules apply. The only difference is that with the exception of dollar signs and the double-quote marks themselves, you don’t need to quote special characters in this context. For example, to print the name of a variable followed by its value, you could write a statement like the following, which prints “The value of $VAR is 3” (with no quotes):

VAR=3
echo "The value of \$VAR is $VAR"

Similarly, you can quote a backslash with another backslash if you need to print it. For example, the following statement prints “This \ is a backslash.“ (again, without quotes):

echo "This \\ is a backslash."

If the character you wish to quote is within single quotes, shell expansion of special characters is disabled entirely. Thus, the only characters that are special are the single-quote marks themselves, because they terminate the single-quote context.

Because special character handling is disabled, a backslash does not quote anything between single-quote marks. Instead, a backslash is interpreted as literal text. Thus, to include a literal single quote within a double-quote context, you must terminate the single-quote context, then include the single quote (either by quoting it with a backslash or by surrounding it with double quotes), then start a new single-quote context.

For example, the following lines of code both print a popular phrase from an American children’s television show:

echo 'It'\''s a beautiful day in the neighborhood.'
echo 'Won'"'"'t you be my neighbor?'

C Shell Note: The C shell does not support using a backslash to quote a character within a double-quoted string. Thus, in the C shell, you print a backslash like this:

echo "This \ is a backslash."
To print a literal dollar sign for a variable name, you must either put the dollar sign in single quotes or quote it with a backslash outside of any quote marks. For example:

echo "This is "'$'"FOO"
echo "This is "\$"FOO"
Both statements print the words “This is $FOO”.

Inline Execution

The Bourne shell provides two operators for executing a command and placing its output in the middle of another command or string. These operators are the $() operator and the back-tick (`) operator (not to be confused with a normal single quote).

One common way to use this is for generating a list of filenames inline. For example, the grep command, when passed the -l flag, returns a list of files that match. This is often combined with the -r flag, which makes grep search recursively for files within any directories that it encounters in its file list. Thus,if you want to edit any files containing "myname" with vi, for example, you could do it like this:

vi $(grep -rl myname directory_of_files)

You can, however, use this to execute any command. There is one small caveat you should be aware of, however. The back-tick operator cannot be nested. For example, the following command produces an error:

FOO=1; BAR=3
echo "Try this command: `echo $FOO + "`expr $BAR + 1`"`"

This fails because the echo command ends at the second back-tick. Thus, the command executed is echo $FOO + ". If you need to nest inline execution, you can use the $() operator for the nested command. For example, the previous example can be written correctly as follows:

FOO=1; BAR=3
echo "Try this command: `echo $FOO + "$(expr $BAR + 1)"`"

You should notice that double quotation marks can be safely nested within a command enclosed by either back-ticks or $().

Note: Evaluation of inline commands, much like expansion of variables, occurs after the statement itself is fully parsed. Thus, it is safe to use either the back-tick or $() operator even if the command may produce double-quote marks in its output. You do not need to quote the resulting content in any way.

C Shell Note: The C shell only partially supports this. It does not support the $() syntax. Its support for the back-tick syntax is somewhat limited; newlines in the result are always stripped and replaced with spaces. If you need to preserve newlines, you should store the results in a temporary file instead of in a shell variable.



< Previous PageNext Page > Hide TOC


Last updated: 2008-04-08




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice