Bash Expansions

Bash Special Parameters Explained with 4 Example Shell Scripts

As part of our on-going bash tutorial series, we discussed about bash positional parameters in our previous article. In this article let us discuss about the bash special parameters with few practical shell script examples.

Some of the bash special parameters that we will discuss in this article are: $*, $@, $#, $$, $!, $?, $-, $_.

To access the whole list of positional parameters, the two special parameters $* and $@ are available. Outside of double quotes, these two are equivalent: Both expand to the list of positional parameters starting with $1 (separated by spaces).

Within double quotes, however, they differ: $* within a pair of double quotes is equivalent to the list of positional parameters, separated by the first character of IFS $1c$2c$3….

$@ within a pair of double quotes is equivalent to the list of positional parameters, separated by unquoted spaces, i.e., $1 $2.. $N.

Example 1: Use Bash $* and $@ to Expand Positional Parameters

This example shows the value available in $* and $@.

First, create the expan.sh as shown below.

$ cat expan.sh
#!/bin/bash

export IFS='-'
cnt=1

# Printing the data available in $*
echo "Values of "$*":"
for arg in "$*"
do
  echo "Arg #$cnt= $arg"
  let "cnt+=1"
done

cnt=1

# Printing the data available in $@
echo "Values of "$@":"
for arg in "$@"
do
  echo "Arg #$cnt= $arg"
  let "cnt+=1"
done

Next, execute the expan.sh as shown below to see how $* and $@ works.

$ ./expan.sh "This is" 2 3
Values of "$*":
Arg #1= This is-2-3
Values of "$@":
Arg #1= This is
Arg #2= 2
Arg #3= 3

Example 2: Use $# to Count Positional Parameters

$# is the special parameter in bash which gives you the number of positional parameter in decimal.

First, create the arithmetic.sh as shown below.

$ cat arithmetic.sh
#!/bin/bash

if [ $# -lt 2 ]
then
  echo "Usage: $0 arg1 arg2"
  exit
fi

echo -e "$1=$1"
echo -e "$2=$2"

let add=$1+$2
let sub=$1-$2
let mul=$1*$2
let div=$1/$2

echo -e "Addition=$add\nSubtraction=$sub\nMultiplication=$mul\nDivision=$div\n"

If the number of positional parameters is less than 2, it will throw the usage information as shown below,

$ ./arithemetic.sh 10
Usage: ./arithemetic.sh arg1 arg2

The special parameter $$ will give the process ID of the shell. $! gives you the process id of the most recently executed background process.

The following script prints the process id of the shell and last execute background process ID.

$ cat proc.sh
#!/bin/bash

echo -e "Process ID=$$"
sleep 1000 &
echo -e "Background Process ID=$!"

Now, execute the above script, and check the process id which its printing.

$ ./proc.sh
Process ID=9502
Background Process ID=9503
$ ps
  PID TTY          TIME CMD
 5970 pts/1    00:00:00 bash
 9503 pts/1    00:00:00 sleep
 9504 pts/1    00:00:00 ps
$

Example 4: Other Bash Special Parameters – $?, $-, $_

$ cat others.sh
#!/bin/bash

echo -e "$_"; ## Absolute name of the file which is being executed

/usr/local/bin/dbhome  # execute the command.
#check the exit status of dbhome
if [ "$?" -ne "0" ]; then
  echo "Sorry, Command execution failed !"
fi

echo -e "$-"; #Set options - hB

echo -e $_  # Last argument of the previous command.

In the above script, the last echo statement echo -e "$_" ($ underscore) also prints hB which is the value of last argument of the previous command. So $_ will give the value after expansion

$ ./others.sh
./others.sh
/home/oracle
Sorry, Command execution failed !
hB
hB

Brace Expansion

Brace expansion is used to generate arbitrary strings. Brace expansion allows you to create multiple modified command line arguments out of a single argument. The specified strings are used to generate all possible combination with the optional surrounding preambles and postscripts. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.

$ echo last{mce,boot,xorg}.log
lastmce.log lastboot.log lastxorg.log

where last is Preamble and .log is the postscript

The above echo statement avoids you to specifying the three log files separately. If you want to view the content of the last boot log, mce log and xorg log you can use the brace expansion as shown in the above echo statement.

1. Example for Backup using brace expansion

$ cat bkup.sh
set -x # expand the commands
da=`date +%F`
cp $da.log{,.bak}

$ ./bkup.sh
++ date +%F
+ da=2010-05-28
+ cp 2010-05-28.log 2010-05-28.log.bak

In the above backup script, it copies the current date log file with the extension .bak. The first element is empty in the braces, so first element will have only preamble.

2. Example for Restore using brace expansion

$ cat restore.sh
set -x # expand the commands
da=`date +%F`
cp $da.log{.bak,}

$ ./restore.sh
++ date +%F
+ da=2010-05-28
+ cp 2010-05-28.log.bak 2010-05-28.log

In the restore script, the first element in the parameter is .bak where as second element is empty.

Also, refer to our earlier article on bash shell functions for additional reading.

3. Example for Brace Expansion without preamble and postscript

If there is no preamble and postscript, it just expands the elements given in the braces.

$ cat expand.sh
echo {oct,hex,dec,bin}

$ ./expand.sh
oct hex dec bin

Without the optional preamble and postscript strings, the result is just a space separated list of the given strings

Brace expansion for Ranges

Brace expansion expands the sequences also. The sequences can be of integers or characters.

4. Example for Integer and character sequences

$ cat sequence.sh
cat /var/log/messages.{1..3}
echo {a..f}{1..9}.txt

$ ./sequence.sh
May  9 01:18:29 x3 ntpd[2413]: time reset -0.132703 s
May  9 01:22:38 x3 ntpd[2413]: synchronized to LOCAL(0), stratum 10
May  9 01:23:44 x3 ntpd[2413]: synchronized to
May  9 01:47:48 x3 dhclient: DHCPREQUEST on eth0
May  9 01:47:48 x3 dhclient: DHCPACK from 23.42.38.201
..
..
a1.txt a2.txt a3.txt a4.txt b1.txt b2.txt b3.txt b4.txt c1.txt c2.txt c3.txt c4.txt

The first cat command, expands messages.1,messages.2 and messages.3 and displays the content. and in the next echo statement character and integer sequences are combined and used.

Sequences with increment value

In kshell brace expansion, you can use increment value, to generate the sequences.

Syntax:
<start>..<end>..<incr>

incr is numeric. You can use a negative integer, but the correct sign is deduced from the order of start and end.

5. Example for using Increment in sequences

$ ksh
$ echo /var/log/messages.{1..7..2}
/var/log/messages.1 /var/log/messages.3 /var/log/messages.5 /var/log/messages.7

Using this you could see the alternate days logfiles.

Pitfall in Brace expansion

Brace expansion does not expand bash variables, because the brace expansion is the very first step of the shell expansion, variable will be expanded later.

6. Example for Variables in expansion

If you see the output of the following two for statement, you could identify the above pitfall.

$ cat var_seq.sh
# Print 1 to 4 using sequences.
for i in {1..4}
do
        echo $i
done
start=1
end=4

# Print 1 to 4 using through variables
echo "Sequences expressed using variables"
for i in {$start..$end}
do
        echo $i
done

$ ./var_seq.sh
1
2
3
4
Sequences expressed using variables
{1..4}

Bash String Manipulation Examples – Length, Substring, Find and Replace

In bash shell, when you use a dollar sign followed by a variable name, shell expands the variable with its value. This feature of shell is called parameter expansion.

But parameter expansion has numerous other forms which allow you to expand a parameter and modify the value or substitute other values in the expansion process. In this article, let us review how to use the parameter expansion concept for string manipulation operations.

1. Identify String Length inside Bash Shell Script

The following format is used to get the length of the given bash variable: ${#string}.

$ cat len.sh
#! /bin/bash

var="Welcome to the geekstuff"

echo ${#var}

$ ./len.sh
24

To understand more about bash variables, read 6 Practical Bash Global and Local Variable Examples.

2. Extract a Substring from a Variable inside Bash Shell Script

Bash provides a way to extract a substring from a string. The following example expains how to parse n characters starting from a particular position.

Extract substring from $string at $position: ${string:position:length}: ${string:position}.

Extract $length of characters substring from $string starting from $position. In the below example, first echo statement returns the substring starting from 15th position. Second echo statement returns the 4 characters starting from 15th position. Length must be the number greater than or equal to zero.

$ cat substr.sh
#! /bin/bash

var="Welcome to the geekstuff"

echo ${var:15}
echo ${var:15:4}

$ ./substr.sh
geekstuff
geek

Also, refer to our earlier article to understand more about $*, $@, $#, $$, $!, $?, $-, $_ bash special parameters.

3. Shortest Substring Match

Following syntax deletes the shortest match of $substring from front of $string: ${string#substring}.

Following syntax deletes the shortest match of $substring from back of $string: ${string%substring}.

Following sample shell script explains the above two shortest substring match concepts.

$ cat shortest.sh
#! /bin/bash

filename="bash.string.txt"

echo ${filename#*.}
echo ${filename%.*}

$ ./shortest.sh
After deletion of shortest match from front: string.txt
After deletion of shortest match from back: bash.string

In the first echo statement substring *. matches the characters and a dot, and # strips from the front of the string, so it strips the substring “bash.” from the variable called filename. In second echo statement substring .* matches the substring starts with dot, and % strips from back of the string, so it deletes the substring .txt

4. Longest Substring Match

Following syntax deletes the longest match of $substring from front of $string: ${string##substring}.

Following syntax deletes the longest match of $substring from back of $string: ${string%%substring}.

Following sample shell script explains the above two longest substring match concepts.

$ cat longest.sh
#! /bin/bash

filename="bash.string.txt"

echo "After deletion of longest match from front:" ${filename##*.}
echo "After deletion of longest match from back:" ${filename%%.*}

$ ./longest.sh
After deletion of longest match from front: txt
After deletion of longest match from back: bash

In the above example, ##\*. strips longest match for '\*.' which matches
"bash.string." so after striping this, it prints the remaining txt. And
%%.\* strips the longest match for .\* from back which matches
".string.txt", after striping  it returns "bash".

5. Find and Replace String Values inside Bash Shell Script

Replace only first match

${string/pattern/replacement}: It matches the pattern in the variable $string, and replace only the first match of the pattern with the replacement.

$ cat firstmatch.sh
#! /bin/bash

filename="bash.string.txt"

echo "After Replacement:" ${filename/str*./operations.}

$ ./firstmatch.sh
After Replacement: bash.operations.txt

Replace all the matches

${string//pattern/replacement}: It replaces all the matches of pattern with replacement.

$ cat allmatch.sh
#! /bin/bash

filename="Path of the bash is /bin/bash"

echo "After Replacement:" ${filename//bash/sh}

$ ./allmatch.sh
After Replacement: Path of the sh is /bin/sh

Taking about find and replace, refer to our earlier articles – sed substitute examples and Vim find and replace.

Replace beginning and end

(${string/#pattern/replacement}) Following syntax replaces with the replacement string, only when the pattern matches beginning of the $string: ${string/%pattern/replacement}.

Following syntax replaces with the replacement string, only when the pattern matches at the end of the given $string.

$ cat posmatch.sh
#! /bin/bash

filename="/root/admin/monitoring/process.sh"

echo "Replaced at the beginning:" ${filename/#\/root/\/tmp}
echo "Replaced at the end": ${filename/%.*/.ksh}

$ ./posmatch.sh
Replaced at the beginning: /tmp/admin/monitoring/process.sh
Replaced at the end: /root/admin/monitoring/process.ksh

Shell Parameter Expansion

The $ character introduces parameter expansion, command substitution, or arithmetic expansion. The parameter name or symbol to be expanded may be enclosed in braces, which are optional but serve to protect the variable to be expanded from characters immediately following it which could be interpreted as part of the name.

When braces are used, the matching ending brace is the first } not escaped by a backslash or within a quoted string, and not within an embedded arithmetic expansion, command substitution, or parameter expansion.

The basic form of parameter expansion is ${parameter}. The value of parameter is substituted. The parameter is a shell parameter as described above (see Shell Parameters) or an array reference (see Arrays). The braces are required when parameter is a positional parameter with more than one digit, or when parameter is followed by a character that is not to be interpreted as part of its name.

If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of indirection. Bash uses the value formed by expanding the rest of parameter as the new parameter; this is then expanded and that value is used in the rest of the expansion, rather than the expansion of the original parameter. This is known as indirect expansion. The value is subject to tilde expansion, parameter expansion, command substitution, and arithmetic expansion. If parameter is a nameref, this expands to the name of the variable referenced by parameter instead of performing the complete indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[@]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.

In each of the cases below, word is subject to tilde expansion, parameter expansion, command substitution, and arithmetic expansion.

When not performing substring expansion, using the form described below (e.g., :-), Bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter`s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.

${parameter:-word} If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

$ v=123
$ echo ${v-unset}
123

${parameter:=word} If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.

$ var=
$ : ${var:=DEFAULT}
$ echo $var
DEFAULT

${parameter:?word} If parameter is null or unset, the expansion of word (or a message to that effect if word is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter is substituted.

$ var=
$ : ${var:?var is unset or null}
bash: var: var is unset or null

${parameter:+word} If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

$ var=123
$ echo ${var:+var is set and not null}
var is set and not null

${parameter:offset} ${parameter:offset:length} This is referred to as Substring Expansion. It expands to up to length characters of the value of parameter starting at the character specified by offset. If parameter is @ or *, an indexed array subscripted by @ or *, or an associative array name, the results differ as described below. If length is omitted, it expands to the substring of the value of parameter starting at the character specified by offset and extending to the end of the value. length and offset are arithmetic expressions (see Shell Arithmetic).

If offset evaluates to a number less than zero, the value is used as an offset in characters from the end of the value of parameter. If length evaluates to a number less than zero, it is interpreted as an offset in characters from the end of the value of parameter rather than a number of characters, and the expansion is the characters between offset and that result. Note that a negative offset must be separated from the colon by at least one space to avoid being confused with the :- expansion.

Here are some examples illustrating substring expansion on parameters and subscripted arrays:

$ string=01234567890abcdefgh
$ echo ${string:7}
7890abcdefgh
$ echo ${string:7:0}

$ echo ${string:7:2}
78
$ echo ${string:7:-2}
7890abcdef
$ echo ${string: -7}
bcdefgh
$ echo ${string: -7:0}

$ echo ${string: -7:2}
bc
$ echo ${string: -7:-2}
bcdef
$ set -- 01234567890abcdefgh
$ echo ${1:7}
7890abcdefgh
$ echo ${1:7:0}

$ echo ${1:7:2}
78
$ echo ${1:7:-2}
7890abcdef
$ echo ${1: -7}
bcdefgh
$ echo ${1: -7:0}

$ echo ${1: -7:2}
bc
$ echo ${1: -7:-2}
bcdef
$ array[0]=01234567890abcdefgh
$ echo ${array[0]:7}
7890abcdefgh
$ echo ${array[0]:7:0}

$ echo ${array[0]:7:2}
78
$ echo ${array[0]:7:-2}
7890abcdef
$ echo ${array[0]: -7}
bcdefgh
$ echo ${array[0]: -7:0}

$ echo ${array[0]: -7:2}
bc
$ echo ${array[0]: -7:-2}
bcdef

If parameter is @ or *, the result is length positional parameters beginning at offset. A negative offset is taken relative to one greater than the greatest positional parameter, so an offset of -1 evaluates to the last positional parameter. It is an expansion error if length evaluates to a number less than zero.

The following examples illustrate substring expansion using positional parameters:

$ set -- 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:7}
7 8 9 0 a b c d e f g h
$ echo ${@:7:0}

$ echo ${@:7:2}
7 8
$ echo ${@:7:-2}
bash: -2: substring expression < 0
$ echo ${@: -7:2}
b c
$ echo ${@:0}
./bash 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${@:0:2}
./bash 1
$ echo ${@: -7:0}

If parameter is an indexed array name subscripted by @ or *, the result is the length members of the array beginning with ${parameter[offset]}. A negative offset is taken relative to one greater than the maximum index of the specified array. It is an expansion error if length evaluates to a number less than zero.

These examples show how you can use substring expansion with indexed arrays:

$ 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
$ echo ${array[@]:7:2}
7 8
$ echo ${array[@]: -7:2}
b c
$ echo ${array[@]: -7:-2}
bash: -2: substring expression < 0
$ echo ${array[@]:0}
0 1 2 3 4 5 6 7 8 9 0 a b c d e f g h
$ echo ${array[@]:0:2}
0 1
$ echo ${array[@]: -7:0}

Substring expansion applied to an associative array produces undefined results.

Substring indexing is zero-based unless the positional parameters are used, in which case the indexing starts at 1 by default. If offset is 0, and the positional parameters are used, $0 is prefixed to the list.

${!prefix*} ${!prefix@} Expands to the names of variables whose names begin with prefix, separated by the first character of the IFS special variable. When @ is used and the expansion appears within double quotes, each variable name expands to a separate word.

${!name[@]} ${!name[*]} If name is an array variable, expands to the list of array indices (keys) assigned in name. If name is not an array, expands to 0 if name is set and null otherwise. When @ is used and the expansion appears within double quotes, each key expands to a separate word.

${#parameter} The length in characters of the expanded value of parameter is substituted. If parameter is * or @, the value substituted is the number of positional parameters. If parameter is an array name subscripted by * or @, the value substituted is the number of elements in the array. If parameter is an indexed array name subscripted by a negative number, that number is interpreted as relative to one greater than the maximum index of parameter, so negative indices count back from the end of the array, and an index of -1 references the last element.

${parameter#word} ${parameter##word} The word is expanded to produce a pattern and matched according to the rules described below (see Pattern Matching). If the pattern matches the beginning of the expanded value of parameter, then the result of the expansion is the expanded value of parameter with the shortest matching pattern (the # case) or the longest matching pattern (the ## case) deleted. If parameter is @ or *, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list.

${parameter%word} ${parameter%%word} The word is expanded to produce a pattern and matched according to the rules described below (see Pattern Matching). If the pattern matches a trailing portion of the expanded value of parameter, then the result of the expansion is the value of parameter with the shortest matching pattern (the % case) or the longest matching pattern (the %% case) deleted. If parameter is @ or *, the pattern removal operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the pattern removal operation is applied to each member of the array in turn, and the expansion is the resultant list.

${parameter/pattern/string} ${parameter//pattern/string} ${parameter/#pattern/string} ${parameter/%pattern/string} The pattern is expanded to produce a pattern just as in filename expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. string undergoes tilde expansion, parameter and variable expansion, arithmetic expansion, command and process substitution, and quote removal. The match is performed according to the rules described below (see Pattern Matching).

In the first form above, only the first match is replaced. If there are two slashes separating parameter and pattern (the second form above), all matches of pattern are replaced with string. If pattern is preceded by # (the third form above), it must match at the beginning of the expanded value of parameter. If pattern is preceded by % (the fourth form above), it must match at the end of the expanded value of parameter. If the expansion of string is null, matches of pattern are deleted. If string is null, matches of pattern are deleted and the / following pattern may be omitted.

If the patsub_replacement shell option is enabled using shopt, any unquoted instances of & in string are replaced with the matching portion of pattern. This is intended to duplicate a common sed idiom.

Quoting any part of string inhibits replacement in the expansion of the quoted portion, including replacement strings stored in shell variables. Backslash will escape & in string; the backslash is removed in order to permit a literal & in the replacement string. Users should take care if string is double-quoted to avoid unwanted interactions between the backslash and double-quoting, since backslash has special meaning within double quotes. Pattern substitution performs the check for unquoted & after expanding string, so users should ensure to properly quote any occurrences of & they want to be taken literally in the replacement and ensure any instances of & they want to be replaced are unquoted.

For instance,

var=abcdef
rep='& '
echo ${var/abc/& }
echo "${var/abc/& }"
echo ${var/abc/$rep}
echo "${var/abc/$rep}"

will display four lines of "abc def", while

var=abcdef
rep='& '
echo ${var/abc/\& }
echo "${var/abc/\& }"
echo ${var/abc/"& "}
echo ${var/abc/"$rep"}

will display four lines of “& def”. Like the pattern removal operators, double quotes surrounding the replacement string quote the expanded characters, while double quotes enclosing the entire parameter substitution do not, since the expansion is performed in a context that doesn`t take any enclosing double quotes into account.

Since backslash can escape `&`, it can also escape a backslash in the replacement string. This means that `\\` will insert a literal backslash into the replacement, so these two echo commands
var=abcdef
rep='\\&xyz'
echo ${var/abc/\\&xyz}
echo ${var/abc/$rep}

will both output \abcxyzdef.

It should rarely be necessary to enclose only string in double quotes.

If the nocasematch shell option (see the description of shopt in The Shopt Builtin) is enabled, the match is performed without regard to the case of alphabetic characters. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

${parameter^pattern} ${parameter^^pattern} ${parameter,pattern} ${parameter,,pattern} This expansion modifies the case of alphabetic characters in parameter. The pattern is expanded to produce a pattern just as in filename expansion. Each character in the expanded value of parameter is tested against pattern, and, if it matches the pattern, its case is converted. The pattern should not attempt to match more than one character.

The ^ operator converts lowercase letters matching pattern to uppercase; the , operator converts matching uppercase letters to lowercase. The ^^ and ,, expansions convert each matched character in the expanded value; the ^ and , expansions match and convert only the first character in the expanded value. If pattern is omitted, it is treated like a ?, which matches every character.

If parameter is @ or *, the case modification operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the case modification operation is applied to each member of the array in turn, and the expansion is the resultant list.

${parameter@operator} The expansion is either a transformation of the value of parameter or information about parameter itself, depending on the value of operator. Each operator is a single letter:

If parameter is @ or *, the operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the operation is applied to each member of the array in turn, and the expansion is the resultant list.

The result of the expansion is subject to word splitting and filename expansion as described below.

Brace Expansion

Brace expansion is a mechanism by which arbitrary strings may be generated. This mechanism is similar to filename expansion (see Filename Expansion), but the filenames generated need not exist. Patterns to be brace expanded take the form of an optional preamble, followed by either a series of comma-separated strings or a sequence expression between a pair of braces, followed by an optional postscript. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.

Brace expansions may be nested. The results of each expanded string are not sorted; left to right order is preserved. For example,

bash$ echo a{d,c,b}e
ade ace abe

A sequence expression takes the form {x..y[..incr]}, where x and y are either integers or letters, and incr, an optional increment, is an integer. When integers are supplied, the expression expands to each number between x and y , inclusive. Supplied integers may be prefixed with ‘0’ to force each term to have the same width. When either x or y begins with a zero, the shell attempts to force all generated terms to contain the same number of digits, zero-padding where necessary. When letters are supplied, the expression expands to each character lexicographically between x and y , inclusive, using the default C locale. Note that both x and y must be of the same type (integer or letter). When the increment is supplied, it is used as the difference between each term. The default increment is 1 or -1 as appropriate.

Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result. It is strictly textual. Bash does not apply any syntactic interpretation to the context of the expansion or the text between the braces.

A correctly-formed brace expansion must contain unquoted opening and closing braces, and at least one unquoted comma or a valid sequence expression. Any incorrectly formed brace expansion is left unchanged.

A { or , may be quoted with a backslash to prevent its being considered part of a brace expression. To avoid conflicts with parameter expansion, the string ${ is not considered eligible for brace expansion, and inhibits brace expansion until the closing }.

This construct is typically used as shorthand when the common prefix of the strings to be generated is longer than in the above example: mkdir /usr/local/src/bash/{old,new,dist,bugs} or chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}.

Tilde Expansion

If a word begins with an unquoted tilde character (~), all of the characters up to the first unquoted slash (or all characters, if there is no unquoted slash) are considered a tilde-prefix. If none of the characters in the tilde-prefix are quoted, the characters in the tilde-prefix following the tilde are treated as a possible login name. If this login name is the null string, the tilde is replaced with the value of the HOME shell variable. If HOME is unset, the home directory of the user executing the shell is substituted instead. Otherwise, the tilde-prefix is replaced with the home directory associated with the specified login name.

If the tilde-prefix is ~+, the value of the shell variable PWD replaces the tilde-prefix. If the tilde-prefix is ~-, the value of the shell variable OLDPWD, if it is set, is substituted.

If the characters following the tilde in the tilde-prefix consist of a number N, optionally prefixed by a + or a -, the tilde-prefix is replaced with the corresponding element from the directory stack, as it would be displayed by the dirs builtin invoked with the characters following tilde in the tilde-prefix as an argument (see The Directory Stack). If the tilde-prefix, sans the tilde, consists of a number without a leading + or -, + is assumed.

If the login name is invalid, or the tilde expansion fails, the word is left unchanged.

Each variable assignment is checked for unquoted tilde-prefixes immediately following a : or the first =. In these cases, tilde expansion is also performed. Consequently, one may use filenames with tildes in assignments to PATH, MAILPATH, and CDPATH, and the shell assigns the expanded value.

The following table shows how Bash treats unquoted tilde-prefixes:

Bash also performs tilde expansion on words satisfying the conditions of variable assignments (see Shell Parameters) when they appear as arguments to simple commands. Bash does not do this, except for the declaration commands listed above, when in POSIX mode.

Word Splitting

The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting.

The shell treats each character of $IFS as a delimiter, and splits the results of the other expansions into words using these characters as field terminators. If IFS is unset, or its value is exactly <space><tab><newline>, the default, then sequences of <space>, <tab>, and <newline> at the beginning and end of the results of the previous expansions are ignored, and any sequence of IFS characters not at the beginning or end serves to delimit words. If IFS has a value other than the default, then sequences of the whitespace characters space, tab, and newline are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character). Any character in IFS that is not IFS whitespace, along with any adjacent IFS whitespace characters, delimits a field. A sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs.

Explicit null arguments (“” or ’’) are retained and passed to commands as empty strings. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed. If a parameter with no value is expanded within double quotes, a null argument results and is retained and passed to a command as an empty string. When a quoted null argument appears as part of a word whose expansion is non-null, the null argument is removed. That is, the word -d'' becomes -d after word splitting and null argument removal.

Note that if no expansion occurs, no splitting is performed.

Filename Expansion

After word splitting, unless the -f option has been set (see The Set Builtin), Bash scans each word for the characters *, ?, and [. If one of these characters appears, and is not quoted, then the word is regarded as a pattern, and replaced with an alphabetically sorted list of filenames matching the pattern (see Pattern Matching). If no matching filenames are found, and the shell option nullglob is disabled, the word is left unchanged. If the nullglob option is set, and no matches are found, the word is removed. If the failglob shell option is set, and no matches are found, an error message is printed and the command is not executed. If the shell option nocaseglob is enabled, the match is performed without regard to the case of alphabetic characters.

When a pattern is used for filename expansion, the character . at the start of a filename or immediately following a slash must be matched explicitly, unless the shell option dotglob is set. In order to match the filenames . and .., the pattern must begin with . (for example, .?), even if dotglob is set. If the globskipdots shell option is enabled, the filenames . and .. are never matched, even if the pattern begins with a .. When not matching filenames, the . character is not treated specially.

When matching a filename, the slash character must always be matched explicitly by a slash in the pattern, but in other matching contexts it can be matched by a special pattern character as described below (see Pattern Matching).

See the description of shopt in The Shopt Builtin, for a description of the nocaseglob, nullglob, globskipdots, failglob, and dotglob options.

The GLOBIGNORE shell variable may be used to restrict the set of file names matching a pattern. If GLOBIGNORE is set, each matching file name that also matches one of the patterns in GLOBIGNORE is removed from the list of matches. If the nocaseglob option is set, the matching against the patterns in GLOBIGNORE is performed without regard to case. The filenames . and .. are always ignored when GLOBIGNORE is set and not null. However, setting GLOBIGNORE to a non-null value has the effect of enabling the dotglob shell option, so all other filenames beginning with a . will match. To get the old behavior of ignoring filenames beginning with a ., make .* one of the patterns in GLOBIGNORE. The dotglob option is disabled when GLOBIGNORE is unset.

Process Substitution

Process substitution allows a process’s input or output to be referred to using a filename. It takes the form of <(list) or >(list).

The process list is run asynchronously, and its input or output appears as a filename. This filename is passed as an argument to the current command as the result of the expansion. If the >(list) form is used, writing to the file will provide input for list. If the <(list) form is used, the file passed as an argument should be read to obtain the output of list. Note that no space may appear between the < or > and the left parenthesis, otherwise the construct would be interpreted as a redirection. Process substitution is supported on systems that support named pipes (FIFOs) or the /dev/fd method of naming open files.

When available, process substitution is performed simultaneously with parameter and variable expansion, command substitution, and arithmetic expansion.

Arithmetic Expansion

Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is: $(( expression )).

The expression undergoes the same expansions as if it were within double quotes, but double quote characters in expression are not treated specially and are removed. All tokens in the expression undergo parameter and variable expansion, command substitution, and quote removal. The result is treated as the arithmetic expression to be evaluated. Arithmetic expansions may be nested.