Custom Shell Scripts

Variables and Quoting

You can play with shell variables in different powerful ways. Very likely, most of the time you will just need to quote those variables properly, so I'll look first at the three kinds of quotes you can use in Bash.

Single quotes (') tell the shell that everything inside them should be used "as is," without any processing. Double quotes (") tell the shell to replace the name of every variable inside the quoted string with its current value. Finally, backquotes (`) tell the shell that the content of the string is a command that should be executed (but only after replacing variables with their values, as in the double quotes case!). An alternative syntax for backquotes is:

#> $(command)

The difference among the three types of quotes is evident in the following example, which you can try out on your system:

#> echo '$PWD'
$PWD
#> echo "$PWD"
/home/marco/
#> echo `$PWD`
bash: /home/marco/: Is a directory

The last command causes an error because the backquotes make the shell grab the value of $PWD (/home/marco/) and then execute /home/marco/ as if it were an executable program, which of course it is not.

Basically, variables in backquote-delimited strings let you build and execute different commands every time they are parsed, depending on the current status of (possibly many) other variables. This is a very powerful feature, especially when you consider that you can nest those strings into each other. In that case, remember to escape the inner backquotes with backslashes.

When quoting, you also have to be careful when you concatenate variables and constant strings. The reason is shown in these commands, which try to assemble a date from its year, month, and day components:

#> YEAR='2018'
#> MONTH='11'
#> DAY=10
#> echo "$YEAR$MONTH$DAY"
20181110
#> echo "$YEAR11$DAY"
10
#> echo "${YEAR}11$DAY"
20181110

The first echo statement works as expected: The shell just concatenated the values of YEAR, MONTH, and DAY to create a date in YYYYMMDD format. The second echo only prints 10 because this time the shell only sees two variables, namely $DAY and $YEAR11, which is undefined. To concatenate a combination of variables and constant strings, you must enclose the name of the variable in braces, as shown in the third echo command.

You can make a variable point to another by combining quotes with exclamation marks:

#> MYNAME=Marco
#> HISNAME=MYNAME
#> echo "his name is $HISNAME"
his name is MYNAME
#> echo "his name is ${!HISNAME}"
his name is Marco

Shell Expansion

The first thing the shell interpreter must do every time it parses a single whole line of a script is to expand it. Expansion consists of looking at each part of the line that is not a Bash built-in command to determine if and how it should be transformed into something else.

This procedure is needed because the actual content and structure of the current line might be different every time that line is parsed. The simplest example of this situation is a line using a variable that corresponds to the current time. In other words, the interpreter cannot know what to do with a line of script without fully expanding it first.

The Bash man page [3] says, "there are seven kinds of expansion performed, in this order: brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, word splitting, and pathname expansion."

This may seem messy, but you already saw most of these expansions: parameter and variable expansion, command substitution, word splitting with IFS, pathname expansion, and tilde expansion with $HOME and ~.

Brace expansion lets you create sequences, or variations of strings with the least possible typing:

#> ATTENDEES=  `echo 'Mr '{John,Frank,William}' Rogers'`
#> echo $ATTENDEES
Mr John Rogers Mr Frank Rogers Mr William Rogers

Another part of shell parsing that may be considered equivalent to expansions is the way backslashes are handled.

Escape characters (i.e., characters preceded by a backslash) have one of two special meanings. If they are alphabetic characters, they are "escape sequences" that tell the shell to perform some action. For example, \a means "ring the alert bell," \n means "go print to the next line,", and \t means "print a horizontal tab."

If the backslash appears before other backslashes and quotes, it tells the shell just to print those characters, without interpreting them: If you type \\, \', or \", the shell will just see and use a single backslash, a single quote, or a double quote, respectively.

Math with Variables

The Bash shell can use variables to do math. By no means is Bash the best tool to do this, but it can do enough things to spare you using another program when you need to do some quick calculations, perhaps as part of a bigger shell script. I will discuss shell math in a later installment, but initially I want to introduce one numeric shell variable, $RANDOM, for two reasons. First, I want to show an example of arithmetic expansion. Second, $RANDOM can be quite useful, even in scripts that are not about numbers. Listing 1 shows a small script using $RANDOM taken from a web page [4] entirely devoted to this variable.

Listing 1

$RANDOM script

01 #! /bin/bash
02 FLOOR=70;
03 CEILING=230;
04 RANGE=$(($CEILING-$FLOOR+1));
05 RESULT=$RANDOM
06 let "RESULT %= $RANGE";
07 RESULT=$(($RESULT+$FLOOR));
08 echo $RESULT

Every time you invoke it, $RANDOM returns a random integer number between 0 and 32,767. The other variables $FLOOR, $CEILING, and $RANGE "translate" that range to make $RESULT a random number between 70 and 230. Lines 4, 6, and 7 show an initial partial example of how to perform math in Bash via arithmetic expansion.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Tutorials – Shell Scripts

    Letting your scripts ask complex questions and give user feedback makes them more effective.

  • Bash Alternatives

    Don't let your familiarity with the Bash shell stop you from exploring other options. We take a look at a pair of alternatives that are easy to install and easy to use: Zsh and fish.

  • Bash vs. Vista PowerShell

    Microsoft’s new PowerShell relies on .NET framework libraries and thus has access to a treasure trove of functions and objects. How does PowerShell measure up to traditional shells like Bash?

  • Bash 4

    Despite the Bourne-again shell's biblical age and high level of maturity, developers continue to work on it. We take a look at the latest Bash release.

  • Bash Tuning

    In the old days, shells were capable of little more than calling external programs and executing basic, internal commands. With all the bells and whistles in the latest versions of Bash, however, you hardly need the support of external tools.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News