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.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
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.
News
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.
-
Latest Cinnamon Desktop Releases with a Bold New Look
Just in time for the holidays, the developer of the Cinnamon desktop has shipped a new release to help spice up your eggnog with new features and a new look.
-
Armbian 24.11 Released with Expanded Hardware Support
If you've been waiting for Armbian to support OrangePi 5 Max and Radxa ROCK 5B+, the wait is over.