2024-04-02 21:19:20 +02:00
|
|
|
---
|
|
|
|
tags:
|
|
|
|
- bash
|
|
|
|
- shell
|
|
|
|
- scripting
|
|
|
|
- expansion
|
|
|
|
- substitution
|
|
|
|
- text
|
|
|
|
- variable
|
|
|
|
- filename
|
|
|
|
- macro
|
|
|
|
- wildcard
|
|
|
|
---
|
2023-07-05 11:43:35 +02:00
|
|
|
|
2024-04-02 21:19:20 +02:00
|
|
|
# Expansions and substitutions
|
2023-07-05 11:43:35 +02:00
|
|
|
|
|
|
|
Before executing your commands, Bash checks whether there are any syntax
|
|
|
|
elements in the command line that should be interpreted rather than
|
|
|
|
taken literally. After splitting the command line into tokens (words),
|
|
|
|
Bash scans for these special elements and interprets them, resulting in
|
|
|
|
a changed command line: the elements are said to be **expanded** to or
|
|
|
|
**substituted** to **new text and maybe new tokens** (words).
|
|
|
|
|
|
|
|
The most simple example of this behaviour is a referenced variable:
|
|
|
|
|
|
|
|
mystring="Hello world"
|
|
|
|
echo "$mystring"
|
|
|
|
|
2024-03-30 20:09:26 +01:00
|
|
|
The `echo` program definitely doesn't care about what a shell variable
|
2024-03-30 19:22:45 +01:00
|
|
|
is. It is Bash's job to deal with the variable. Bash **expands** the
|
2024-10-08 06:00:17 +02:00
|
|
|
string "`$mystring`" to "`Hello world`", so that `echo` will only
|
2023-07-05 11:43:35 +02:00
|
|
|
see `Hello world`, not the variable or anything else!
|
|
|
|
|
|
|
|
After all these expansions and substitutions are done, all quotes that
|
|
|
|
are not meant literally (i.e., [the quotes that marked contiguous
|
2024-01-29 02:07:56 +01:00
|
|
|
words](../../syntax/quoting.md), as part of the shell syntax) are removed from
|
2024-03-30 20:09:26 +01:00
|
|
|
the commandline text, so the called program won't see them. This step
|
2023-07-05 11:43:35 +02:00
|
|
|
is called **quote-removal**.
|
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
2024-03-30 20:09:26 +01:00
|
|
|
Saw a possible expansion syntax but don't know what it is? Here's a
|
2023-07-05 11:43:35 +02:00
|
|
|
small list.
|
|
|
|
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Parameter expansion](../../syntax/pe.md) (it has its own [overview
|
|
|
|
section](../../syntax/pe.md#overview))
|
2023-07-05 11:43:35 +02:00
|
|
|
- `$WORD`
|
|
|
|
- `${STUFF...}`
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Pathname expansion](../../syntax/expansion/globs.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- `*.txt`
|
|
|
|
- `page_1?.html`
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Arithmetic expansion](../../syntax/expansion/arith.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- `$(( EXPRESSION ))`
|
|
|
|
- `$[ EXPRESSION ]`
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Command substitution](../../syntax/expansion/cmdsubst.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- `$( COMMAND )`
|
|
|
|
- `` ` COMMAND ` ``
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Tilde expansion](../../syntax/expansion/tilde.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- `~`
|
|
|
|
- `~+`
|
|
|
|
- `~-`
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Brace expansion](../../syntax/expansion/brace.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- `{X,Y,Z}`
|
|
|
|
- `{X..Y}`
|
|
|
|
- `{X..Y..Z}`
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Process substitution](../../syntax/expansion/proc_subst.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- `<( COMMAND )`
|
|
|
|
- `>( COMMAND )`
|
|
|
|
|
|
|
|
## Order
|
|
|
|
|
|
|
|
Bash performs expansions and substitutions in a defined order. This
|
|
|
|
explains why globbing (pathname expansion), for example, is safe to use
|
|
|
|
on filenames with spaces (because it happens **after** the final word
|
|
|
|
splitting!).
|
|
|
|
|
|
|
|
The order is (from first to last):
|
|
|
|
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Brace expansion](../../syntax/expansion/brace.md)
|
|
|
|
- [Tilde expansion](../../syntax/expansion/tilde.md)
|
2023-07-05 11:43:35 +02:00
|
|
|
- The following expansions happen at the same time, in a left-to-right
|
|
|
|
fashion on the commandline (see below)
|
2024-01-29 02:07:56 +01:00
|
|
|
- [Parameter expansion](../../syntax/pe.md)
|
|
|
|
- [Arithmetic expansion](../../syntax/expansion/arith.md)
|
|
|
|
- [Command substitution](../../syntax/expansion/cmdsubst.md)
|
|
|
|
- [Word splitting](../../syntax/expansion/wordsplit.md)
|
|
|
|
- [Pathname expansion](../../syntax/expansion/globs.md)
|
|
|
|
|
|
|
|
[Process substitution](../../syntax/expansion/proc_subst.md) is performed
|
|
|
|
**simultaneously** with [parameter expansion](../../syntax/pe.md), [command
|
|
|
|
substitution](../../syntax/expansion/cmdsubst.md) and [arithmetic
|
|
|
|
expansion](../../syntax/expansion/arith.md). It is only performed when the
|
2023-07-05 11:43:35 +02:00
|
|
|
underlying operating system supports it.
|
|
|
|
|
2024-01-29 02:07:56 +01:00
|
|
|
The 3 steps [parameter expansion](../../syntax/pe.md), [arithmetic
|
|
|
|
expansion](../../syntax/expansion/arith.md) and [command
|
|
|
|
substitution](../../syntax/expansion/cmdsubst.md) happen at the same time in a
|
2023-07-05 11:43:35 +02:00
|
|
|
left-to-right fashion on nthe commandline. This means
|
|
|
|
|
|
|
|
i=1
|
|
|
|
echo $i $((i++)) $i
|
|
|
|
|
|
|
|
will output `1 1 2` and not `1 1 1`.
|