Shell – Difference between expansion and substitution in shell scripting terminology

shell-scriptterminology

Expansion and Substitution seems to be interchangeble at same context in shell programming language. For example, some documents such as Bash reference manual, Bash Hackers Wiki use the word 'expansion' to explain 'shell parameter expansion'. However, some other documents seem to prefer the word 'substitution'. Advanced Bash-Scripting Guide uses parameter substituion.

Is there any difference between 'expansion' and 'substitution' in terms of shell programming terminology?

Best Answer

Substitution is almost synonymous with expansion in this context because their meanings overlap. Neither is quite a complete sub category of the other, although in the GNU Manual section you reference there are substitutions that are considered as part of an overall expansion.

An expansion is extracting the value of an identifier. E.g., if this=that, when we expand this we get that. An expansion that doesn't involve substitution is pre-determined in that the value used already exists and must simply be retrieved, although this includes combining retrieved/explicit values (such as with "arithmetic expansion").

A substitution creates a value as the result of an explicit input/output operation. E.g., if this=$(foo bar), this is the result of executing foo bar and capturing its output.1 Although the value resulting from a substitution maybe completely predictable, it is different from the one retrieved in a normal expansion because it does not actually exist until the substitution takes place -- it is produced.

Substitutions come in two flavours, command and process, which are sort of symmetrical:

# Command substitution
foo=$(ls)
# Process substitution
wc <(ls)

The "command" in first one is ls, as is the "process" in the second one. We might say what is being substituted is really the end of a pipe. Process substitution overlaps with redirection. However, this is probably a bit too under-the-hood restrictive technically, which brings us to the footnote...


  1. foo bar in this case could be an internal shell function, in which case it there's no interprocess IO. The existence of shell built-ins less obviously obscures this difference. In terms of content the input and output will be the same.
Related Question