Step 1 of 5 · Reading · ~3 min
Read
Built-ins & Variables
Variables and Parameter Expansion
After this lesson your shell keeps a table of variables and rewrites a typed line by replacing $NAME, ${NAME} and the ${NAME:-default} family with their values, while single quotes, double quotes and backslashes decide what is protected. The output is the line after quote removal, exactly as the next stage would see it.
Where expansion sits
Expansion is the third stage, after tokenizing and parsing and before execution. It works on the text of a word, which is why quoting matters here too: the shell has to know, character by character, whether a $ is live.
Where the $ is | Expanded? |
|---|---|
| unquoted | yes |
inside "..." | yes |
inside '...' | no, everything is literal |
| after a backslash outside quotes | no, the backslash is dropped and the $ is kept |
Quote removal happens in the same pass: the quote characters and the backslashes that did escaping disappear. Inside double quotes a backslash only escapes $, a backtick, " and a backslash; before anything else it stays.
The forms to support (POSIX 2.6.2)
| Form | Result |
|---|---|
$NAME or ${NAME} | the value, or nothing when unset |
${NAME:-word} | the value, or word when the variable is unset or empty |
${NAME:=word} | the same, and also stores word in the variable |
${NAME:+word} | word when the variable is set and non-empty, otherwise nothing |
${#NAME} | the number of characters in the value, 0 when unset |
A name is a letter or underscore followed by letters, digits and underscores. The short form $NAME takes the longest such name, so $AB is the variable AB and ${A}B is A followed by B. A $ followed by anything else (a digit, a space, the end of the text) is just a dollar sign here; positional parameters are outside this lesson.
The word part is itself expanded, so ${A:-${B}} works, and a } that closes an inner ${ does not close the outer one. A ${ with no matching } or a body that is not one of these forms is a bad substitution. A quote that never closes is an error too.
A worked trace
With HOME set to /home/ann and ROLE unset, take "$HOME" '$HOME' ${ROLE:-guest}. The walk meets a double quote, so it enters quoted mode, expands $HOME to /home/ann and leaves at the closing quote. Next the single quotes copy $HOME untouched. Then ${ROLE:-guest} finds ROLE unset and yields guest. The quote marks are dropped, so the result is /home/ann $HOME guest.
Why there is no word splitting here
A real shell also splits the results of unquoted expansions on whitespace and expands wildcards. Those are separate steps: this lesson prints one string and leaves spacing exactly as the variable held it.
Common mistakes
- Expanding inside single quotes, or forgetting that double quotes still expand.
- Treating
${X:-d}as${X-d}. The colon makes an empty value count as unset. - Reading
$NAMEfooas$NAMEfollowed by foo. The shell reads the whole name, so it is the variableNAMEfoo. - Letting an inner
}close the whole expression.
Your exercise
The starter holds the variable table and the command loop for SET, UNSET and EXPAND. You write the function that expands one line. The most likely mistake is treating a backslash the same inside and outside double quotes.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…