Skip to content

Expansion

When we type a command with arguments/inputs and press the enter key, the shell does several things to the arguments/input text before it actually carries out the command. This action is called expansion. With expansion, the arguments expands into something else before the shell acts on it with the command. Let's see an example with echo command which prints out the text arguments given on standard output.

input
echo hello world!
output
hello world!

Let's use echo with *:

input
echo *
output
hello.c hello.qsub hello.sb README

Instead of printing *, it prints out all file names in the directory because shell expands * into something else before the echo command acts on the argument (in this case *).

input
ls
output
hello.c hello.qsub hello.sb README

The * character is called a "wildcard" is replaced by everything in the current directory. We can also modify it so that it's only replaced by certain things. For example, h* is replaced everything that starts with h in the current directory.

input
echo h*
output
hello.c hello.qsub hello.sb

~ is another special character with a special meaning. It expands into the name of the home directory of the user:

input
echo ~
output
/mnt/home/temp_user_01

The shell will also expand arithmetic. Arithmetic expansion uses the form $((expression)). Look at the example.

input
echo $((1 + 1))
output
2

Please keep in mind that arithmetic expansions allows only integers. Arithmetic expression can be nested, and spaces are allowed.

input
echo $(( 7*( 2 + 2 ) ))
output
28
input
echo $((7*(2+2)))
output
28

Brace expansion is useful when you write a shell script or batch script. The brace expression can contain a comma separated list of characters, strings, or integers that will be expanded into multiple expressions. Here are a few examples.

input
echo srt-{a,b,c}-end
output
srt-a-end srt-b-end srt-c-end
input
echo number_{1..5}
output
number_1 number_2 number_3 number_4 number_5
input
echo {A..Z}

``` output title="output"
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
input
echo a{A{1,5},B{6..10}}b
output
aA1b aA5b aB6b aB7b aB8b aB9b aB10b

The next example creates multiple directories with a brace expansion.

input
mkdir Photos
cd Photos/
mkdir {2020..2021}-{01..12}
ls
output
2020-01/  2020-03/  2020-05/  2020-07/  2020-09/  2020-11/  2021-01/  2021-03/  2021-05/  2021-07/  2021-09/  2021-11/
2020-02/  2020-04/  2020-06/  2020-08/  2020-10/  2020-12/  2021-02/  2021-04/  2021-06/  2021-08/  2021-10/  2021-12/

Expansion also allows us to use the output of a command in different places. The syntax is the same as arithmetic expansion, except the command is placed inside $(...)

input
echo $(ls | grep 2020)
output
2020-01/ 2020-02/ 2020-03/ 2020-04/ 2020-05/ 2020-06/ 2020-07/ 2020-08/ 2020-09/ 2020-10/ 2020-11/ 2020-12/

Next, let's learn how to control expansion. Consider the following two examples where automatic expansion doesn't do what we want.

input
echo This is a      test
output
This is a test
input
echo The total is $100.00
output
The total is 00.00

In the first example, the shell removes extra space from the echo command's argument. In the second example, $1 is interpreted as the first input parameter which is not defined here, and therefore, it is replaced as empty string. With quoting, we can suppress unwanted expansions.

First, let's learn about double quotes. If we place text inside double quotes, parameters are not split by white space and all special characters lose their special meaning, and are treated as ordinary characters. However $, \ (backslash), and ` (back quote) are exceptions.

input
echo "This is a     test"
output
This is a     test
input
echo "The total is $100.00"
output
The total is 00.00

Here is another example where the shell splitting the parameters by white space would cause a problem. Suppose that our working directory has the file two words.txt in it, where the filename has a space.

input
ls two words.txt
output
ls: cannot access two: No such file or directory
ls: cannot access words.txt: No such file or directory

The shell splits the two words and looks for them each separately with ls. Quoting fixes this.

input
ls "two words.txt"
output
two words.txt

If you want to suppress all expansions, you need to use single quotes.

input
echo 'This is a     test'
output
This is a     test
input
echo 'The total is $100.00'
output
The total is $100.00

The next three examples show how quoting gives different results.

input
echo text ~/*.txt {1..5} $(echo foo) $((2+2)) $(date)
output
text /mnt/home/user_name/hostfile.txt /mnt/home/user_name/powertools.txt 
1 2 3 4 5 foo 4 Tue Jan 19 15:10:00 EST 2021
input
echo "text ~/*.txt {1..5} $(echo foo) $((2+2)) $(date)"
output
text ~/*.txt {1..5} foo 4 Tue Jan 19 15:10:09 EST 2021
input
echo 'text ~/*.txt {1..5} $(echo foo) $((2+2)) $(date)'
text ~/*.txt {1..5} $(echo foo) $((2+2)) $(date)

A backslash is useful when we want to quote a single character. A backslash is called the escape character. Next example shows how quoting and an escape character work.

input
echo The balance of $(date) is $100
output
The balance of Tue Jan 19 15:15:36 EST 2021 is 00
input
echo "The balance of $(date) is $100"
output
The balance of Tue Jan 19 15:15:48 EST 2021 is 00
input
echo 'The balance of $(date) is $100'
output
The balance of $(date) is $100
input
echo "The balance of $(date) is \$100"
output
The balance of Tue Jan 19 15:16:09 EST 2021 is $100
input
echo 'The balance of $(date) is \$100'
output
The balance of $(date) is \$100

The table show the most frequently used escape characters.

Escape Character Name usage
\n newline Adding blank lines to text
\t tab Inserting horizontal tabs to text
\a alert Making the user terminal beep
\\ backslash Inserting a backslash