Bash Expansion
Contents
History Expansion
In an interactive shell, the exclamation mark (!) triggers history expansion of the command prompt. This allows the expansion of tokens into (parts of) previous commands.
Commands can be accessed by index or by search:
!1 expands to the first command; !-1 expands to the most recent command
!! is an alias to !-1
!foo expands to the most recent command that began with foo
!? is an alias for the most recent command matching the most recent search term
A command selection can be pared down to specific tokens. These tokens can be accessed by index, anchor, or search:
!!:0 expands to the first token in the most recent command; !!:1 expands to the second token; and so on
!!:^ expands to the first argument (i.e. the second token: !!:1); !!:$ expands to the last token
!!:% expands to the first token matching the most recent search term
!!:a-b for any integers a and b expands to the list of tokens identified by those indices, inclusive
!!:-b is an alias for !!:0-b
!!:a* is an alias for !!:a-$
!!:a- is an alias for !!:a-$ excluding the last token
!!:- is an alias for !!:0-
Note that for all of these except index-based selections, the colon (:) can be omitted.
A number of modifiers also are available. These must be separated from the command and word selections by a colon (:). Additionally, while modifiers can be chained, they each must be separated by colons.
Modifier |
Meaning |
h |
remove the trailing filename or subdirectory from a path |
t |
remove all preceding path elements from a filename or subsidrectory path |
r |
remove a trailing filename suffix from a basename |
e |
remove all preceding name elements from a filename suffix |
p |
echo the expanded command without executing |
q |
quote the expansion as a single token |
x |
quote the expansion's tokens |
s |
s/foo/bar/ replaces foo with bar |
& |
The most recent s modification |
g |
Apply modifications to the entire command prompt |
a |
Alias of g |
G |
Apply the following s or & modification to apply to each token individually |
Note that if g is combined with s or & modifiers, the colon can be omitted (i.e. !!:gs/foo/bar/).
Brace Expansion
{a,b} is expanded to the tokens a and b. This can be used like:
cp /path/to/file/example{,.bak} # or touch example.{c,h}
Sequence Expansion
{1..3} is expanded to the tokens 1, 2, and 3.
An increment can be optionally specified like {1..3..1}.
If the first number is larger than the second, then the token expands to a decreasing sequence. Behind the scenes, in this case, the increment defaulted to -1.
Tilde Expansion
The tilde (~) expands to a directory. Which directory depends on what, if any, characters follow it.
Tilde Prefix |
Expansion |
~ |
$HOME |
~/foo |
$HOME/foo |
~me/foo |
subdirectory foo within the home directory of user me |
~+/foo |
$PWD/foo |
~-/foo |
if $OLDPWD is set, $OLDPWD/foo |
~N |
for an integer N, the Nth element in the directory stack (dirs +N) |
~+N |
for an integer N, the Nth element in the directory stack (dirs +N) |
~-N |
for an integer N, the -Nth element in the directory stack (dirs -N) |
Parameter Expansion
The simplest form of parameter expansion is ${parameter}.
Conditional Parameter Expansion
Conditional parameter expansions provide default values if the parameter is unset or empty.
Suppose that:
export a=a export b= unset c
Operator |
Parameter Expansion |
Value |
Side Effects |
:- |
${a:-d} |
a |
|
:- |
${b:-d} |
d |
|
:- |
${c:-d} |
d |
|
- |
${a-d} |
a |
|
- |
${b-d} |
|
|
- |
${c-d} |
d |
|
:= |
${a:=d} |
a |
|
:= |
${b:=d} |
d |
b is set to d |
:= |
${c:=d} |
d |
c is set to d |
= |
${a=d} |
a |
|
= |
${b=d} |
|
|
= |
${c=d} |
d |
c is set to d |
:? |
${a:?d} |
a |
|
:? |
${b:?d} |
d |
shell exits |
:? |
${c:?d} |
d |
shell exits |
? |
${a?d} |
a |
|
? |
${b?d} |
|
|
? |
${c?d} |
d |
shell exits |
:+ |
${a:+d} |
d |
|
:+ |
${b:+d} |
|
|
:+ |
${c:+d} |
|
|
+ |
${a+d} |
d |
|
+ |
${b+d} |
d |
|
+ |
${c+d} |
|
|
The general rules are that:
including a colon (:) checks for unset and empty values; excluding it checks for only unset values
the subtraction sign (-) uses the left value value if possible, otherwise uses the right hand value
the equals sign (=) uses the left value value if possible, otherwise uses the right hand value and set the left hand value to be equal to the right hand value
the question mark (?) uses the left value value if possible, otherwise throws an error and exits the shell
the plus sign (+) uses the right value value if the left hand value is available, otherwise is empty
Substring Parameter Expansion
Strings can be sliced in parameter expansion.
string=01234567890abcdefgh echo ${string:7} # 7890abcdefgh echo ${string:7:2} # 78 echo ${string:7:-2} # 7890abcdef echo ${string: -7} # bcdefgh echo ${string: -7:-2} # bcdef
Arrays use the same syntax if they are subscripted with [@] or [*].
array=(0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h) echo ${array[@]:7} # 7 8 9 0 a b c d e f g h
Indirect Parameter Expansion
If a parameter expansion begins with !, then the expansion is interpretted as input for another expansion.
export foo=bar export bar=baz echo ${foo} # bar echo ${!foo} # baz
Arithmetic Expansion
$(( 1 + 1 )) expands to 2. For a description of all arithmetic operators, see here.
The tokens within an arithmetic expansion undergo all of the above and below expansions individually. Arithmetic expansion can be nested.
Variables are expanded, though an empty or unset variable expands to 0. In addition, if a variable expands to anything that is not a number, that evaluation is interpretted as input for another expansion.
A string literal will not expand, and in fact will raise an error.
Command Expansion
$(date) expands to the output of date.
The commands are executed in a subshell, so all side-effects are discarded.
Command expansion can be nested.
Process Expansion
Commands can be expanded to file-like objects.
To provide a command's STDIN as a file-like object to another command, try:
date > >(cat)
To provide a command's STDOUT as a file-like object to another command, try:
cat <(date)
Word Splitting
A command is split into tokens using $IFS. (The default is spaces, tabs, and newlines.) Leading and trailing instances of $IFS are ignored. Repeated instances of any member of $IFS are treated as a singular delimiter for splitting.
Literal null tokens ("" or '') are kept and passed to commands. On the other hand, unquoted null tokens (as resulting from expansions) are removed. The exception is if such an expansion happens within double quotes (such as "$var"), in which case a null token is kept. Note that when such an expansion is part of a larger, non-null token (such as "x$var"), the null expansion part is removed.
Filename Expansion
The unquoted characters *, ?, and [ trigger filename expansion.
* matches any 0 or more characters. When the globstar option is enabled, ** matches all files and directories and **/ matches all directories.
? matches any 1 character.
[...] matches any character contained within the brackets.
Quoting
To avoid ambiguity with variable expansion, ${ is not eligible for these types of expansion.
{ and , may be quoted within brace expansion to ensure they are interpretted as literal characters.