Skip to content

3. Expansion

When we type a command with arguments/inputs and press the enter key, 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. We already learned echo command in the previous section. As you know, echo prints out its text arguments on standard output.

1
2
$ echo hello world!
hello world!

Let's use echo with '*':

1
2
$ echo *
hello.c hello.qsub hello.sb README

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

1
2
3
4
5
$ ls
hello.c hello.qsub hello.sb README

$ echo h*
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:

1
2
$ echo ~
$ temp_user_01

The shell allows arithmetic by expansion. Arithmetic expansion uses the form $((expression)). Look at the example.

1
2
$ echo $((1 + 1))
2

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

1
2
3
4
$ echo $(( 7*( 2 + 2 ) ))
28
$ echo $((7*(2+2)))
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. Here is a few examples.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ echo srt-{a,b,c}-end
srt-a-end srt-b-end srt-c-end

$ echo number_{1..5}
number_1 number_2 number_3 number_4 number_5

$ echo {A..Z}
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

$ echo a{A{1,5},B{6..10}}b
aA1b aA5b aB6b aB7b aB8b aB9b aB10b

The next example is creating multiple directories with a brace expansion.

1
2
3
4
5
6
7
$ mkdir Photos
$ cd Photos/
Photos$ mkdir {2020..2021}-{01..12}
Photos$ ls
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/
Photos$

Expansion also allows us to use the output of a command.

1
2
$ echo $(ls |grep 2020)
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. 

1
2
3
4
5
$ echo This is a      test
This is a test

$ echo The total is $100.00
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 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, all special characters lose their special meaning, and treated as ordinary characters. However "$" "\" (backslash) and "`" (back quote) are exceptions.

1
2
3
4
5
6
7
8
$ echo "This is a     test"
This is a     test

$ ls two words.txt
ls: cannot access two: No such file or directory
ls: cannot access words.txt: No such file or directory
(base) dev-intel16-k80:shell$ ls "two words.txt"
two words.txt

If you want to suppress all expansions, you need to use single quotes. Next three examples show how quoting give different results.

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

$ echo "text ~/*.txt {1..5} $(echo foo) $((2+2)) $(date)"
text ~/*.txt {1..5} foo 4 Tue Jan 19 15:10:09 EST 2021
$ 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 wan to quote a single character. A backslash is called the escape character. Next example shows how quoting and an escape character work.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ echo The balance of $(date) is $100
The balance of Tue Jan 19 15:15:36 EST 2021 is 00

$ echo "The balance of $(date) is $100"
The balance of Tue Jan 19 15:15:48 EST 2021 is 00

$ echo 'The balance of $(date) is $100'
The balance of $(date) is $100

$ echo "The balance of $(date) is \$100"
The balance of Tue Jan 19 15:16:09 EST 2021 is $100

$ echo 'The balance of $(date) is \$100'
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