0% found this document useful (0 votes)
89 views18 pages

An Introduction To Programming With Bash

This document provides an introduction to programming with the Bash shell. It discusses Bash as both a command line interface and a programming language. It covers basic Bash syntax and tools, including variables, control operators, and built-in commands. The document is divided into three chapters that cover syntax and tools, logical operators and shell expansions, and loops to enable repetitive operations in Bash scripts.

Uploaded by

aristidezz
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
89 views18 pages

An Introduction To Programming With Bash

This document provides an introduction to programming with the Bash shell. It discusses Bash as both a command line interface and a programming language. It covers basic Bash syntax and tools, including variables, control operators, and built-in commands. The document is divided into three chapters that cover syntax and tools, logical operators and shell expansions, and loops to enable repetitive operations in Bash scripts.

Uploaded by

aristidezz
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 18

Opensource.

com

An introduction to
programming with Bash
Opensource.com . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

About Opensource.com

What is Opensource.com?

Opensource.com publishes stories about creating,


adopting, and sharing open source
solutions. Visit Opensource.com to learn more about how the open source
way is improving technologies, education, business, government, health, law,
entertainment, humanitarian efforts, and more.

Submit a story idea: opensource.com/story

Email us: open@opensource.com

2 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . About the Author

David Both

David Both is an Open Source Software and GNU/Linux advocate, trainer,


writer, and speaker who lives in Raleigh North Carolina. He is a
strong proponent of and evangelist for the “Linux Philosophy.”
David has been in the IT industry for nearly 50 years. He has taught RHCE classes for
Red Hat and has worked at MCI Worldcom, Cisco, and the State of North Carolina. He has
been working with Linux and Open Source Software for over 20 years.
David prefers to purchase the components and build his own computers from scratch to
ensure that each new computer meets his exacting specifications. His primary workstation
is an ASUS TUF X299 motherboard and an Intel i9 CPU with 16 cores (32 CPUs) and
64GB of RAM in a ThermalTake Core X9 case.
David has written articles for magazines including, Linux Magazine and Linux Journal. His
article “Complete Kickstart,” co-authored with a colleague at Cisco, was ranked 9th in the Linux
Magazine Top Ten Best System Administration Articles list for 2008. David currently writes
prolifically for OpenSource.com and Enable SysAdmin.
He currently has four books published at Apress,
“The Linux Philosophy for SysAdmins,” and “Using
and Administering Linux: Zero to SysAdmin,” a Linux
self-study training course in three volumes.

Follow David Both

Email: LinuxGeek46@both.org
Twitter: @LinuxGeek46

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 3


Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapters

Syntax and tools 5

Logical operators and shell expansions 9

Loops 15

4 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Syntax and tools

Syntax and tools


Learn basic Bash programming syntax and tools, as well as how to use
variables and control operators, in the first part in this three-part guide.

A shell is the command interpreter for the oper-


ating system. Bash is my favorite shell,
but every Linux shell interprets the commands typed by the
a form the operating system can use. When the results
are returned to the shell program, it displays them in the
terminal. All of the shells I am familiar with are also pro-
user or sysadmin into a form gramming languages.
the operating system can Bash stands for Bourne
use. When the results are re- Again Shell because the
turned to the shell program, Bash shell is based upon [3]
it sends them to STDOUT the older Bourne shell that
which, by default, displays was written by Steven Bourne
them in the terminal [1]. All of in 1977. Many other shells [4]
the shells I am familiar with are available, but these are
are also programming lan- the four I encounter most
guages. frequently:
Features like tab comple- • csh: The C shell for pro-
tion, command-line recall and grammers who like the
editing, and shortcuts like syntax of the C language
aliases all contribute to its value as a powerful shell. Its default • ksh: The Korn shell, written by David Korn and popular
command-line editing mode uses Emacs, but one of my favor- with Unix users
ite Bash features is that I can change it to Vi mode to use ed- • tcsh: A version of csh with more ease-of-use features
iting commands that are already part of my muscle memory. • zsh: The Z shell, which combines many features of other
However, if you think of Bash solely as a shell, you miss popular shells
much of its true power. While researching my three-volume All shells have built-in commands that supplement or re-
Linux self-study course [2] (on which this guide is based), I place the ones provided by the core utilities. Open the shell’s
learned things about Bash that I’d never known in over 20 man page and find the “BUILT-INS” section to see the com-
years of working with Linux. Some of these new bits of knowl- mands it provides.
edge relate to its use as a programming language. Bash is a Each shell has its own personality and syntax. Some will
powerful programming language, one perfectly designed for work better for you than others. I have used the C shell, the
use on the command line and in shell scripts. Korn shell, and the Z shell. I still like the Bash shell more than
This three-part guide explores using Bash as a command-line any of them. Use the one that works best for you, although
interface (CLI) programming language. This first part looks at that might require you to try some of the others. Fortunately,
some simple command-line programming with Bash, variables, it’s quite easy to change shells.
and control operators. The other parts explore types of Bash All of these shells are programming languages, as well as
files; string, numeric, and miscellaneous logical operators that command interpreters. Here’s a quick tour of some program-
provide execution-flow control logic; different types of shell ex- ming constructs and tools that are integral parts of Bash.
pansions; and the for, while, and until loops that enable re-
petitive operations. They will also look at some commands that Bash as a programming language
simplify and support the use of these tools. Most sysadmins have used Bash to issue commands that
are usually fairly simple and straightforward. But Bash can
The shell go beyond entering single commands, and many sysadmins
A shell is the command interpreter for the operating sys- create simple command-line programs to perform a series
tem. Bash is my favorite shell, but every Linux shell inter- of tasks. These programs are common tools that can save
prets the commands typed by the user or sysadmin into time and effort.

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 5


Syntax and tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

My objective when writing CLI programs is to save time That may not seem like much of a program, but it is the first
and effort (i.e., to be the lazy sysadmin). CLI programs program I encounter with every new programming language
support this by listing several commands in a specific se- I learn. The syntax may be a bit different for each language,
quence that execute one after another, so you do not need but the result is the same.
to watch the progress of one command and type in the Let’s expand a little on this trivial but ubiquitous program.
next command when the first finishes. You can go do other Your results will be different from mine because I have done
things and not have to continually monitor the progress of other experiments, while you may have only the default
each command. directories and files that are created in the account home
directory the first time you log into an account via the GUI
What is “a program”? desktop.
The Free On-line Dictionary of Computing (FOLDOC) [5]
defines a program as: “The instructions executed by a com- [student@studentvm1 ~]$ echo "My home directory." ; ls ;
puter, as opposed to the physical device on which they run.” My home directory.
Princeton University’s WordNet [6] defines a program as: ch
apter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt
“…a sequence of instructions that a computer can interpret softlink1 testdir6
and execute…” Wikipedia [7] also has a good entry about ch
apter26 TestFile1.mac dmesg3.txt file005 Pictures
computer programs. Templates testdir
Therefore, a program can consist of one or more instructions Te
stFile1 Desktop dmesg.txt link3 Public
that perform a specific, related task. A computer program in- testdir Videos
struction is also called a program statement. For sysadmins, Te
stFile1.dos dmesg1.txt Documents Music random.txt
a program is usually a sequence of shell commands. All the testdir1
shells available for Linux, at least the ones I am familiar with,
have at least a basic form of programming capability, and Bash, That makes a bit more sense. The results are related, but
the default shell for most Linux distributions, is no exception. the individual program statements are independent of each
While this guide uses Bash (because it is so ubiquitous), if other. Notice that I like to put spaces before and after the
you use a different shell, the general programming concepts semicolon because it makes the code a bit easier to read.
will be the same, although the constructs and syntax may dif- Try that little CLI program again without an explicit semicolon
fer somewhat. Some shells may support some features that at the end:
others do not, but they all provide some programming capa-
bility. Shell programs can be stored in a file for repeated use, [student@studentvm1 ~]$ echo "My home directory." ; ls
or they may be created on the command line as needed.
There is no difference in the output.
Simple CLI programs
The simplest command-line programs are one or two con- Something about variables
secutive program statements, which may be related or not, Like all programming languages, the Bash shell can deal
that are entered on the command line before the Enter key with variables. A variable is a symbolic name that refers
is pressed. The second statement in a program, if there is to a specific location in memory that contains a value of
one, might be dependent upon the actions of the first, but it some sort. The value of a variable is changeable, i.e., it
does not need to be. is variable.
There is also one bit of syntactical punctuation that needs Bash does not type variables like C and related languag-
to be clearly stated. When entering a single command on the es, defining them as integers, floating points, or string types.
command line, pressing the Enter key terminates the com- In Bash, all variables are strings. A string that is an integer
mand with an implicit semicolon (;). When used in a CLI shell can be used in integer arithmetic, which is the only type of
program entered as a single line on the command line, the math that Bash is capable of doing. If more complex math
semicolon must be used to terminate each statement and is required, the bc command can be used in CLI programs
separate it from the next one. The last statement in a CLI and scripts.
shell program can use an explicit or implicit semicolon. Variables are assigned values and can be used to refer to
those values in CLI programs and scripts. The value of a vari-
Some basic syntax able is set using its name but not preceded by a $ sign. The
The following examples will clarify this syntax. This program assignment VAR=10 sets the value of the variable VAR to 10.
consists of a single command with an explicit terminator: To print the value of the variable, you can use the statement
echo $VAR. Start with text (i.e., non-numeric) variables.
[student@studentvm1 ~]$ echo "Hello world." ; Bash variables become part of the shell environment until
Hello world. they are unset.

6 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Syntax and tools

Check the initial value of a variable that has not been as- Those commands all run without a problem so long as no
signed; it should be null. Then assign a value to the variable errors occur. But what happens when an error occurs?
and print it to verify its value. You can do all of this in a single You can anticipate and allow for errors using the built-in
CLI program: && and || Bash control operators. These two control op-
erators provide some flow control and enable you to alter
[student@studentvm1 ~]$ echo $MyVar ; MyVar="Hello World" ; the sequence of code execution. The semicolon is also
echo $MyVar ; considered to be a Bash control operator, as is the new-
line character.
Hello World The && operator simply says, “if command1 is successful,
[student@studentvm1 ~]$ then run command2. If command1 fails for any reason, then
command2 is skipped.” That syntax looks like this:
Note: The syntax of variable assignment is very strict. There
must be no spaces on either side of the equal (=) sign in the command1 && command2
assignment statement.
The empty line indicates that the initial value of MyVar is null. Now, look at some commands that will create a new direc-
Changing and setting the value of a variable are done the same tory and—if it’s successful—make it the present working di-
way. This example shows both the original and the new value. rectory (PWD). Ensure that your home directory (~) is the
As mentioned, Bash can perform integer arithmetic cal- PWD. Try this first in /root, a directory that you do not have
culations, which is useful for calculating a reference to the access to:
location of an element in an array or doing simple math prob-
lems. It is not suitable for scientific computing or anything [student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir/ && cd $Dir
that requires decimals, such as financial calculations. There mkdir: cannot create directory '/root/testdir/': Permission denied
are much better tools for those types of calculations. [student@studentvm1 ~]$
Here’s a simple calculation:
The error was emitted by the mkdir command. You did not
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = receive an error indicating that the file could not be created
$((Var1*Var2))" because the creation of the directory failed. The && con-
Result = 63 trol operator sensed the non-zero return code, so the touch
command was skipped. Using the && control operator pre-
What happens when you perform a math operation that re- vents the touch command from running because there was
sults in a floating-point number? an error in creating the directory. This type of command-line
program flow control can prevent errors from compounding
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = and making a real mess of things. But it’s time to get a little
$((Var1/Var2))" more complicated.
Result = 0 The || control operator allows you to add another program
[student@studentvm1 ~]$ Var1="7" ; Var2="9" ; echo "Result = statement that executes when the initial program statement re-
$((Var2/Var1))" turns a code greater than zero. The basic syntax looks like this:
Result = 1
[student@studentvm1 ~]$ command1 || command2

The result is the nearest integer. Notice that the calculation This syntax reads, “If command1 fails, execute command2.”
was performed as part of the echo statement. The math is That implies that if command1 succeeds, command2 is
performed before the enclosing echo command due to the skipped. Try this by attempting to create a new directory:
Bash order of precedence. For details see the Bash man
page and search “precedence.” [student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir || echo
"$Dir was not created."
Control operators mk
dir: cannot create directory '/root/testdir': Permission
Shell control operators are one of the syntactical oper- denied
ators for easily creating some interesting command-line /root/testdir was not created.
programs. The simplest form of CLI program is just string- [student@studentvm1 ~]$
ing several commands together in a sequence on the
command line: This is exactly what you would expect. Because the new di-
rectory could not be created, the first command failed, which
command1 ; command2 ; command3 ; command4 ; . . . ; etc. ; resulted in the execution of the second command.

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 7


Syntax and tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Combining these two operators provides the best of [student@studentvm1 testdir]$ ll ; echo "RC = $?"
both. The control operator syntax using some flow control total 1264
takes this general form when the && and || control oper- drwxrwxr-x 2 student student 4096 Mar 2 08:21 chapter25
ators are used: drwxrwxr-x 2 student student 4096 Mar 21 15:27 chapter26
-rwxr-xr-x 1 student student 92 Mar 20 15:53 TestFile1
pr
eceding commands ; command1 && command2 || command3 ; <snip>
following commands drwxrwxr-x. 2 student student 663552 Feb 21 14:12 testdir
drwxr-xr-x. 2 student student 4096 Dec 22 13:15 Videos
This syntax can be stated like so: “If command1 exits with a RC = 0
return code of 0, then execute command2, otherwise exe- [student@studentvm1 testdir]$
cute command3.” Try it:
The RC, in this case, is zero, which means the command
[student@studentvm1 ~]$ Dir=/root/testdir ; mkdir $Dir && cd completed successfully. Now try the same command on
$Dir || echo "$Dir was not created." root’s home directory, a directory you do not have permis-
mk
dir: cannot create directory '/root/testdir': Permission sions for:
denied
/root/testdir was not created. [student@studentvm1 testdir]$ ll /root ; echo "RC = $?"
[student@studentvm1 ~]$ ls: cannot open directory '/root': Permission denied
RC = 2
Now try the last command again using your home directory [student@studentvm1 testdir]$
instead of the /root directory. You will have permission to
create this directory: In this case, the RC is two; this means permission was de-
nied for a non-root user to access a directory to which the
[s
tudent@studentvm1 ~]$ Dir=~/testdir ; mkdir $Dir && cd $Dir user is not permitted access. The control operators use
|| echo "$Dir was not created." these RCs to enable you to alter the sequence of program
[student@studentvm1 testdir]$ execution.

The control operator syntax, like command1 && com- Summary


mand2, works because every command sends a return This part looked at Bash as a programming language and
code (RC) to the shell that indicates if it completed suc- explored its basic syntax as well as some basic tools. It
cessfully or whether there was some type of failure during showed how to print data to STDOUT and how to use vari-
execution. By convention, an RC of zero (0) indicates suc- ables and control operators. The next part in this guide looks
cess, and any positive number indicates some type of fail- at some of the many Bash logical operators that control the
ure. Some of the tools sysadmins use just return a one (1) flow of instruction execution.
to indicate a failure, but many use other codes to indicate
the type of failure that occurred. Links
The Bash shell variable $? contains the RC from the last [1]  https://opensource.com/article/18/10/linux-data-streams
command. This RC can be checked very easily by a script, [2]  http://www.both.org/?page_id=1183
the next command in a list of commands, or even the sys- [3]  https://opensource.com/19/9/command-line-heroes-bash
admin directly. Start by running a simple command and im- [4] https://en.wikipedia.org/wiki/Comparison_of_command_
mediately checking the RC. The RC will always be for the shells
last command that ran before you looked at it. [5] http://foldoc.org/program
[6] https://wordnet.princeton.edu/
[7] https://en.wikipedia.org/wiki/Computer_program

8 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Logical operators and shell expansions

Logical operators
and shell expansions
Learn about logical operators and shell expansions, in the second
part in this three-part guide on programming with Bash.

Logical operators are the basis


for making de-
cisions in a program and executing different sets of instruc-
Bash can perform on files. I use them quite frequently in
my scripts.

tions based on those decisions. This is sometimes called Operator Description


flow control.
-a filename True if the file exists; it can be empty or
have some content but, so long as it exists,
Logical operators this will be true
Bash has a large set of logical operators that can be used
in conditional expressions. The most basic form of the if -b filename True if the file exists and is a block special
file such as a hard drive like /dev/sda or
control structure tests for a condition and then executes
/dev/sda1
a list of program statements if the condition is true. There
are three types of operators: file, numeric, and non-numeric -c filename True if the file exists and is a character
special file such as a TTY device like
operators. Each operator returns true (0) if the condition is
/dev/TTY1
met and false (1) if the condition is not met.
The functional syntax of these comparison operators is -d filename True if the file exists and is a directory
one or two arguments with an operator that are placed with- -e filename True if the file exists; this is the same as
in square braces, followed by a list of program statements -a above
that are executed if the condition is true, and an optional list -f filename True if the file exists and is a regular
of program statements if the condition is false: file, as opposed to a directory, a device
special file, or a link, among others
if [ arg1 operator arg2 ] ; then list -g filename True if the file exists and is set-group-id,
or SETGID
if [ arg1 operator arg2 ] ; then list ; else list ; fi
-h filename True if the file exists and is a symbolic link

The spaces in the comparison are required as shown. The -k filename True if the file exists and its “sticky’” bit
is set
single square braces, [ and ], are the traditional Bash sym-
bols that are equivalent to the test command: -p filename True if the file exists and is a named pipe
(FIFO)
if test arg1 operator arg2 ; then list -r filename True if the file exists and is readable, i.e.,
has its read bit set
There is also a more recent syntax that offers a few advan- -s filename True if the file exists and has a size great-
tages and that some sysadmins prefer. This format is a bit er than zero; a file that exists but that has
less compatible with different versions of Bash and other a size of zero will return false
shells, such as ksh (the Korn shell). It looks like: -t fd True if the file descriptor fd is open and
refers to a terminal
if [[ arg1 operator arg2 ]] ; then list
-u filename True if the file exists and its set-user-id
bit is set
File operators
-w filename True if the file exists and is writable
File operators are a powerful set of logical operators within
Bash. Figure 1 lists more than 20 different operators that -x filename True if the file exists and is executable

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 9


Logical operators and shell expansions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

-G filename True if the file exists and is owned by the [student@studentvm1 testdir]$ File="TestFile1" ; echo "This
effective group ID is file $File" > $File ; if [ -s $File ] ; then echo "$File
-L filename True if the file exists and is a symbolic link exists and contains data." ; fi
-N filename True if the file exists and has been modi- TestFile1 exists and contains data.
fied since it was last read [student@studentvm1 testdir]$
-O filename True if the file exists and is owned by the
effective user ID That works, but it is only truly accurate for one specific con-
-S filename True if the file exists and is a socket dition out of the three possible ones. Add an else stanza so
file1 -ef file2 True if file1 and file2 refer to the same you can be somewhat more accurate, and delete the file so
device and iNode numbers you can fully test this new code:
file1 -nt file2 True if file1 is newer (according to mod-
ification date) than file2, or if file1 exists [student@studentvm1 testdir]$ File="TestFile1" ; rm $File ; if
and file2 does not [ -s $File ] ; then echo "$File exists and contains data." ;

file1 -ot file2 True if file1 is older than file2, or if file2 else echo "$File does not exist or is empty." ; fi
exists and file1 does not TestFile1 does not exist or is empty.

Fig. 1: The Bash file operators Now create an empty file to test:
As an example, start by testing for the existence of a file:
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ;
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] if [ -s $File ] ; then echo "$File exists and contains data." ;
; then echo "The file $File exists." ; else echo "The file $File else echo "$File does not exist or is empty." ; fi
does not exist." ; fi TestFile1 does not exist or is empty.
The file TestFile1 does not exist.
[student@studentvm1 testdir]$ Add some content to the file and test again:

Next, create a file for testing named TestFile1. For now, it [student@studentvm1 testdir]$ File="TestFile1" ; echo "This
does not need to contain any data: is file $File" > $File ; if [ -s $File ] ; then echo "$File
exists and contains data." ; else echo "$File does not exist
[student@studentvm1 testdir]$ touch TestFile1 or is empty." ; fi
TestFile1 exists and contains data.
It is easy to change the value of the $File variable rather
than a text string for the file name in multiple locations in this Now, add the elif stanza to discriminate between a file that
short CLI program: does not exist and one that is empty:

[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] [student@studentvm1 testdir]$ File="TestFile1" ; touch $File ;


; then echo "The file $File exists." ; else echo "The file $File if [ -s $File ] ; then echo "$File exists and contains data." ;
does not exist." ; fi elif [ -e $File ] ; then echo "$File exists and is empty." ;
The file TestFile1 exists. else echo "$File does not exist." ; fi
[student@studentvm1 testdir]$ Te
stFile1 exists and is empty.
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is
Now, run a test to determine whether a file exists and has $File" > $File ; if [ -s $File ] ; then echo "$File exists and
a non-zero length, which means it contains data. You want contains data." ; elif [ -e $File ] ; then echo "$File exists
to test for three conditions: 1. the file does not exist; 2. the and is empty." ; else echo "$File does not exist." ; fi
file exists and is empty; and 3. the file exists and contains Te
stFile1 exists and contains data.
data. Therefore, you need a more complex set of tests— [student@studentvm1 testdir]$
use the elif stanza in the if-elif-else construct to test for
all of the conditions: Now you have a Bash CLI program that can test for these
three different conditions… but the possibilities are endless.
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -s $File ] It is easier to see the logic structure of the more complex
; then echo "$File exists and contains data." ; fi compound commands if you arrange the program state-
[student@studentvm1 testdir]$ ments more like you would in a script that you can save in
a file. Figure 2 shows how this would look. The indents of
In this case, the file exists but does not contain any data. Add the program statements in each stanza of the if-elif-else
some data and try again: structure help to clarify the logic.

10 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Logical operators and shell expansions

File="TestFile1" [student@studentvm1 testdir]$ MyVar="Random text" ; if [ -z


echo "This is $File" > $File "" ] ; then echo "MyVar is zero length." ; else echo "MyVar
if [ -s $File ] contains data" ; fi
then MyVar is zero length.
echo "$File exists and contains data."
elif [ -e $File ] You could also do it this way:
then
echo "$File exists and is empty." [student@studentvm1 testdir]$ MyVar="Random text" ; if [ -n
else "$MyVar" ] ; then echo "MyVar contains data." ; else echo
echo "$File does not exist." "MyVar is zero length" ; fi
fi MyVar contains data.
[student@studentvm1 testdir]$ MyVar="" ; if [ -n "$MyVar" ] ;
Fig. 2: The command line program rewritten as it would appear
in a script then echo "MyVar contains data." ; else echo "MyVar is zero
length" ; fi
Logic this complex is too lengthy for most CLI programs. MyVar is zero length
Although any Linux or Bash built-in commands may be
used in CLI programs, as the CLI programs get longer and Sometimes you may need to know a string’s exact length.
more complex, it makes more sense to create a script that This is not a comparison, but it is related. Unfortunately,
is stored in a file and can be executed at any time, now or there is no simple way to determine the length of a string.
in the future. There are a couple of ways to do it, but I think using the
expr (evaluate expression) command is easiest. Read the
String comparison operators man page for expr for more about what it can do. Note
String comparison operators enable the comparison of al- that quotes are required around the string or variable
phanumeric strings of characters. There are only a few of you’re testing.
these operators, which are listed in Figure 3.
[student@studentvm1 testdir]$ MyVar="" ; expr length "$MyVar"

Operator Description 0
[student@studentvm1 testdir]$ MyVar="How long is this?" ; expr
-z string True if the length of string is zero
length "$MyVar"
-n string True if the length of string is non-zero 17
string1 == string2 True if the strings are equal; a single [student@studentvm1 testdir]$ expr length "We can also find the
or = should be used with the test com- length of a literal string as well as a variable."
string1 = string2 mand for POSIX conformance. When 70
used with the [[ command, this per-
forms pattern matching as described Regarding comparison operators, I use a lot of testing
above (compound commands). in my scripts to determine whether two strings are equal
string1 != string2 True if the strings are not equal (i.e., identical). I use the non-POSIX version of this com-
parison operator:
string1 < string2 True if string1 sorts before string2 lex-
icographically (refers to locale-specif-
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello
ic sorting sequences for all alphanu-
World" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches
meric and special characters)
Var2" ; else echo "Var1 and Var2 do not match." ; fi
string1 > string2 True if string1 sorts after string2 lexi- Va
r1 matches Var2
cographically
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello
Fig. 3: Bash string logical operators world" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches
Var2" ; else echo "Var1 and Var2 do not match." ; fi
First, look at string length. The quotes around $MyVar in the Va
r1 and Var2 do not match.
comparison must be there for the comparison to work. (You
should still be working in ~/testdir.) Experiment some more on your own to try out these operators.

[student@studentvm1 testdir]$ MyVar="" ; if [ -z "" ] ; then Numeric comparison operators


echo "MyVar is zero length." ; else echo "MyVar contains Numeric operators make comparisons between two numeric
data" ; fi arguments. Like the other operator classes, most are easy
MyVar is zero length. to understand.

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 11


Logical operators and shell expansions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Operator Description
expansion can be used to generate lists of arbitrary strings
arg1 -eq arg2 True if arg1 equals arg2 and insert them into a specific location within an enclosing
arg1 -ne arg2 True if arg1 is not equal to arg2 static string or at either end of a static string. This may be
arg1 -lt arg2 True if arg1 is less than arg2 hard to visualize, so it’s best to just do it.
First, here’s what a brace expansion does:
arg1 -le arg2 True if arg1 is less than or equal to arg2
arg1 -gt arg2 True if arg1 is greater than arg2 [student@studentvm1 testdir]$ echo {string1,string2,string3}
arg1 -ge arg2 True if arg1 is greater than or equal to arg2 string1 string2 string3

Fig. 4: Bash numeric comparison logical operators


Well, that is not very helpful, is it? But look what happens
Here are some simple examples. The first instance sets the when you use it just a bit differently:
variable $X to 1, then tests to see if $X is equal to 1. In the
second instance, X is set to 0, so the comparison is not true. [student@studentvm1 testdir]$ echo "Hello "{David,Jen,Rikki,Jason}.
Hello David. Hello Jen. Hello Rikki. Hello Jason.
[student@studentvm1 testdir]$ X=1 ; if [ $X -eq 1 ] ; then echo
"X equals 1" ; else echo "X does not equal 1" ; fi That looks like something useful—it could save a good deal
X equals 1 of typing. Now try this:
[student@studentvm1 testdir]$ X=0 ; if [ $X -eq 1 ] ; then echo
"X equals 1" ; else echo "X does not equal 1" ; fi [student@studentvm1 testdir]$ echo b{ed,olt,ar}s
X does not equal 1 beds bolts bars
[student@studentvm1 testdir]$
I could go on, but you get the idea.
Try some more experiments on your own.
Tilde expansion
Miscellaneous operators Arguably, the most common expansion is the tilde (~) expan-
These miscellaneous operators show whether a shell option sion. When you use this in a command like cd ~/Documents,
is set or a shell variable has a value, but it does not discover the Bash shell expands it as a shortcut to the user’s full home
the value of the variable, just whether it has one. directory.
Use these Bash programs to observe the effects of the
Operator Description tilde expansion:
-o optname True if the shell option optname is enabled
[student@studentvm1 testdir]$ echo ~
(see the list of options under the descrip-
/home/student
tion of the -o option to the Bash set builtin
[student@studentvm1 testdir]$ echo ~/Documents
in the Bash man page)
/home/student/Documents
-v varname True if the shell variable varname is set [student@studentvm1 testdir]$ Var1=~/Documents ; echo $Var1 ;
(has been assigned a value) cd $Var1
-R varname True if the shell variable varname is set /home/student/Documents
and is a name reference [student@studentvm1 Documents]$

Fig. 5: Miscellaneous Bash logical operators


Pathname expansion
Experiment on your own to try out these operators. Pathname expansion is a fancy term expanding file-glob-
bing patterns, using the characters ? and *, into the full
Expansions names of directories that match the pattern. File globbing
Bash supports a number of types of expansions and substi- refers to special pattern characters that enable significant
tutions that can be quite useful. According to the Bash man flexibility in matching file names, directories, and other
page, Bash has seven forms of expansions. This part looks at strings when performing various actions. These special
five of them: tilde expansion, arithmetic expansion, pathname pattern characters allow matching single, multiple, or spe-
expansion, brace expansion, and command substitution. cific characters in a string.

Brace expansion • ? — Matches only one of any character in the specified


Brace expansion is a method for generating arbitrary location within the string
strings. (This tool is used below to create a large number of • * — Matches zero or more of any character in the specified
files for experiments with special pattern characters.) Brace location within the string

12 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Logical operators and shell expansions

This expansion is applied to matching directory names. [student@studentvm1 testdir]$ touch Downtown ; ls -d Do*
To see how this works, ensure that testdir is the pres- Documents Downloads Downtown
ent working directory (PWD) and start with a plain listing [student@studentvm1 testdir]$
(the contents of my home directory will be different from
yours): This shows the file, too. So any files that match the pattern
are also expanded to their full names.
[student@studentvm1 testdir]$ ls
ch
apter6 cpuHog.dos dmesg1.txt Documents Music Command substitution
softlink1 testdir6 Videos Command substitution is a form of expansion that allows the
ch
apter7 cpuHog.Linux dmesg2.txt Downloads Pictures STDOUT data stream of one command to be used as the ar-
Templates testdir gument of another command; for example, as a list of items
te
stdir cpuHog.mac dmesg3.txt file005 Public to be processed in a loop. The Bash man page says: “Com-
testdir tmp mand substitution allows the output of a command to replace
cp
uHog Desktop dmesg.txt link3 random.txt the command name.” I find that to be accurate if a bit obtuse.
testdir1 umask.test There are two forms of this substitution, `command` and
[student@studentvm1 testdir]$ $(command). In the older form using back tics (`), using
a backslash (\) in the command retains its literal meaning.
Now list the directories that start with Do, testdir/Docu- However, when it’s used in the newer parenthetical form, the
ments, and testdir/Downloads: backslash takes on its meaning as a special character. Note
also that the parenthetical form uses only single parentheses
Documents: to open and close the command statement.
Di
rectory01 file07 file15 test02 test10 test20 I frequently use this capability in command-line programs
testfile13 TextFiles and scripts where the results of one command can be used
Di
rectory02 file08 file16 test03 test11 testfile01 as an argument for another command.
testfile14 Start with a very simple example that uses both forms of
fil
e01 file09 file17 test04 test12 testfile04 this expansion (again, ensure that testdir is the PWD):
testfile15
fil
e02 file10 file18 test05 test13 testfile05 [student@studentvm1 testdir]$ echo "Todays date is `date`"
testfile16 Todays date is Sun Apr 7 14:42:46 EDT 2019
fil
e03 file11 file19 test06 test14 testfile09 [student@studentvm1 testdir]$ echo "Todays date is $(date)"
testfile17 Todays date is Sun Apr 7 14:42:59 EDT 2019
fil
e04 file12 file20 test07 test15 testfile10 [student@studentvm1 testdir]$
testfile18
fil
e05 file13 Student1.txt test08 test16 testfile11 The -w option to the seq utility adds leading zeros to the
testfile19 numbers generated so that they are all the same width,
file06 file14 test01 test09 test18 testfile12 i.e., the same number of digits regardless of the value. This
testfile20 makes it easier to sort them in numeric sequence.
The seq utility is used to generate a sequence of numbers:
Downloads:
[student@studentvm1 testdir]$ [student@studentvm1 testdir]$ seq 5
1
Well, that did not do what you wanted. It listed the contents of 2
the directories that begin with Do. To list only the directories 3
and not their contents, use the -d option. 4
5
[student@studentvm1 testdir]$ ls -d Do* [student@studentvm1 testdir]$ echo `seq 5`
Documents Downloads 1 2 3 4 5
[student@studentvm1 testdir]$ [student@studentvm1 testdir]$

In both cases, the Bash shell expands the Do* pattern Now you can do something a bit more useful, like creating a
into the names of the two directories that match the large number of empty files for testing:
pattern. But what if there are also files that match the
pattern? [s
tudent@studentvm1 testdir]$ for I in $(seq -w 5000) ; do
touch file-$I ; done

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 13


Logical operators and shell expansions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

In this usage, the statement seq -w 5000 generates a list Here is a simple calculation I often do in a script or CLI
of numbers from one to 5,000. By using command substi- program that tells me how much total virtual memory I
tution as part of the for statement, the list of numbers is have in a Linux host. The free command does not provide
used by the for statement to generate the numerical part that data:
of the file names.
[student@studentvm1 testdir]$ RAM=`free | grep ^Mem | awk
Arithmetic expansion '{print $2}'` ; Swap=`free | grep ^Swap | awk '{print $2}'`
Bash can perform integer math, but it is rather cumbersome ; echo "RAM = $RAM and Swap = $Swap" ; echo "Total Virtual
(as you will soon see). The syntax for arithmetic expansion memory is $((RAM+Swap))" ;
is $((arithmetic-expression)), using double parentheses RA
M = 4037080 and Swap = 6291452
to open and close the expression. Total Virtual memory is 10328532
Arithmetic expansion works like command substitution
in a shell program or script; the value calculated from the I used the ` character to delimit the sections of code used for
expression replaces the expression for further evaluation command substitution.
by the shell. I use Bash arithmetic expansion mostly for checking sys-
Once again, start with something simple: tem resource amounts in a script and then choose a program
execution path based on the result.
[student@studentvm1 testdir]$ echo $((1+1))
2 Summary
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; This part, the second in this guide on Bash as a program-
Var3=$((Var1*Var2)) ; echo "Var 3 = $Var3" ming language, explored the Bash file, string, numeric,
Var 3 = 35 and miscellaneous logical operators that provide exe-
cution-flow control logic and the different types of shell
The following division results in zero because the result expansions.
would be a decimal value of less than one: The third part in this guide will explore the use of loops
for performing various types of iterative operations.
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1/
Var2)) ; echo "Var 3 = $Var3"
Var 3 = 0

14 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Loops

Loops
Learn how to use loops for performing iterative operations, in the
final part in this three-part guide on programming with Bash.

Every programming language I have ever used has


at least a couple types of loop structures
that provide various capabilities to perform repetitive op-
[student@studentvm1 testdir]$ for Dept in "Human Resources"
Sales Finance "Information Technology" Engineering
Administration Research ; do echo "Department $Dept" ; done
erations. I use the for loop quite often but I also find the Department Human Resources
while and until loops useful. Department Sales
Department Finance
for loops Department Information Technology
Bash’s implementation of the for command is, in my opinion, Department Engineering
a bit more flexible than most because it can handle non-nu- Department Administration
meric values; in contrast, for example, the standard C lan- Department Research
guage for loop can deal only with numeric values.
The basic structure of the Bash version of the for command Make some directories (and show some progress informa-
is simple: tion while doing so):

for Var in list1 ; do list2 ; done [student@studentvm1 testdir]$ for Dept in "Human Resources"
Sales Finance "Information Technology" Engineering
This translates to: “For each value in list1, set the $Var to Administration Research ; do echo "Working on Department
that value and then perform the program statements in list2 $Dept" ; mkdir "$Dept" ; done
using that value; when all of the values in list1 have been Working on Department Human Resources
used, it is finished, so exit the loop.” The values in list1 can Working on Department Sales
be a simple, explicit string of values, or they can be the result Working on Department Finance
of a command substitution (described in the second part in Working on Department Information Technology
the guide). I use this construct frequently. Working on Department Engineering
To try it, ensure that ~/testdir is still the present working Working on Department Administration
directory (PWD). Clean up the directory, then look at a trivial Working on Department Research
example of the for loop starting with an explicit list of values. [student@studentvm1 testdir]$ ll
This list is a mix of alphanumeric values—but do not forget total 28
that all variables are strings and can be treated as such. drwxrwxr-x 2 student student 4096 Apr 8 15:45 Administration
drwxrwxr-x 2 student student 4096 Apr 8 15:45 Engineering
[student@studentvm1 testdir]$ rm * drwxrwxr-x 2 student student 4096 Apr 8 15:45 Finance
[student@studentvm1 testdir]$ for I in a b c d 1 2 3 4 ; do drwxrwxr-x 2 student student 4096 Apr 8 15:45 'Human Resources'
echo $I ; done drwxrwxr-x 2 student student 4096 Apr 8 15:45 'Information
a Technology'
b drwxrwxr-x 2 student student 4096 Apr 8 15:45 Research
c drwxrwxr-x 2 student student 4096 Apr 8 15:45 Sales
d
1 The $Dept variable must be enclosed in quotes in the mkdir
2 statement; otherwise, two-part department names (such as
3 “Information Technology”) will be treated as two separate de-
4 partments. That highlights a best practice I like to follow: all
file and directory names should be a single word. Although
Here is a bit more useful version with a more meaningful most modern operating systems can deal with spaces in
variable name: names, it takes extra work for sysadmins to ensure that

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 15


Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

those special cases are considered in scripts and CLI pro- rpcbind-1.2.5-0.fc29.x86_64
grams. (They almost certainly should be considered, even libsss_sudo-2.0.0-5.fc29.x86_64
if they’re annoying because you never know what files you libfontenc-1.1.3-9.fc29.x86_64
will have.) <snip>
So, delete everything in ~/testdir—again—and do this
one more time: Add the sort and uniq commands to sort the list and print
the unique ones (since it’s possible that some RPMs with
[student@studentvm1 testdir]$ rm -rf * ; ll identical names are installed):
total 0
[student@studentvm1 testdir]$ for Dept in Human-Resources Sales [student@studentvm1 testdir]$ rpm -qa | sort | uniq
Finance Information-Technology Engineering Administration a2ps-4.14-39.fc29.x86_64
Research ; do echo "Working on Department $Dept" ; mkdir aajohan-comfortaa-fonts-3.001-3.fc29.noarch
"$Dept" ; done abattis-cantarell-fonts-0.111-1.fc29.noarch
Working on Department Human-Resources abiword-3.0.2-13.fc29.x86_64
Working on Department Sales abrt-2.11.0-1.fc29.x86_64
Working on Department Finance abrt-addon-ccpp-2.11.0-1.fc29.x86_64
Working on Department Information-Technology abrt-addon-coredump-helper-2.11.0-1.fc29.x86_64
Working on Department Engineering abrt-addon-kerneloops-2.11.0-1.fc29.x86_64
Working on Department Administration abrt-addon-pstoreoops-2.11.0-1.fc29.x86_64
Working on Department Research abrt-addon-vmcore-2.11.0-1.fc29.x86_64
[student@studentvm1 testdir]$ ll <snip>
total 28
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Administration Since this gives the correct list of RPMs you want to look at,
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Engineering you can use this as the input list to a loop that will print all the
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Finance details of each RPM:
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Human-Resources
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Information- [student@studentvm1 testdir]$ for RPM in `rpm -qa | sort |
Technology uniq` ; do rpm -qi $RPM ; done
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Research
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Sales This code produces way more data than you want. Note that
the loop is complete. The next step is to extract only the in-
Suppose someone asks for a list of all RPMs on a partic- formation the PHBs requested. So, add an egrep command,
ular Linux computer and a short description of each. This which is used to select ^Name or ^Summary. The carat (^)
happened to me when I worked for the State of North Caro- specifies the beginning of the line; thus, any line with Name
lina. Since open source was not “approved” for use by state or Summary at the beginning of the line is displayed.
agencies at that time, and I only used Linux on my desktop
computer, the pointy-haired bosses (PHBs) needed a list of
each piece of software that was installed on my computer so [student@studentvm1 testdir]$ for RPM in `rpm -qa | sort |
that they could “approve” an exception. uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary"
How would you approach that? Here is one way, starting Name : a2ps
with the knowledge that the rpm –qa command provides a Summary : Converts text and other types of files to
complete description of an RPM, including the two items the PostScript
PHBs want: the software name and a brief summary. Name : aajohan-comfortaa-fonts
Build up to the final result one step at a time. First, list Summary : Modern style true type font
all RPMs: Name : abattis-cantarell-fonts
Summary : Humanist sans serif font
[student@studentvm1 testdir]$ rpm -qa Name : abiword
perl-HTTP-Message-6.18-3.fc29.noarch Summary : Word processing program
perl-IO-1.39-427.fc29.x86_64 Name : abrt
perl-Math-Complex-1.59-429.fc29.noarch Summary : Automatic bug detection and reporting tool
lua-5.3.5-2.fc29.x86_64 <snip>
java-11-openjdk-headless-11.0.ea.28-2.fc29.x86_64
util-linux-2.32.1-1.fc29.x86_64 You can try grep instead of egrep in the command above,
libreport-fedora-2.9.7-1.fc29.x86_64 but it will not work. You could also pipe the output of this

16 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com


. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Loops

command through the less filter to explore the results. 4


The final command sequence looks like this: 5
6
[s
tudent@studentvm1 testdir]$ for RPM in `rpm -qa | sort | 7
uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary" > 8
RPM-summary.txt 9
[student@studentvm1 testdir]$
This command-line program uses pipelines, redirection, and
a for loop—all on a single line. It redirects the output of your This CLI program should make more sense now that you
little CLI program to a file that can be used in an email or as have studied its parts. First, it sets $X to zero in case it has
input for other purposes. a value left over from a previous program or CLI command.
This process of building up the program one step at a time Then, since the logical expression [ true ] always evaluates
allows you to see the results of each step and ensure that it to 1, which is true, the list of program instructions between
is working as you expect and provides the desired results. do and done is executed forever—or until you press Ctrl+C
From this exercise, the PHBs received a list of over or otherwise send a signal 2 to the program. Those instruc-
1,900 separate RPM packages. I seriously doubt that any- tions are an arithmetic expansion that prints the current val-
one read that list. But I gave them exactly what they asked ue of $X and then increments it by one.
for, and I never heard another word from them about it. One of the tenets of The Linux Philosophy for Sysadmins [2]
is to strive for elegance, and one way to achieve elegance is
Other loops simplicity. You can simplify this program by using the variable
There are two more types of loop structures available in increment operator, ++. In the first instance, the current value
Bash: the while and until structures, which are very similar of the variable is printed, and then the variable is incremented.
to each other in both syntax and function. The basic syntax This is indicated by placing the ++ operator after the variable:
of these loop structures is simple:
[student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((X++)) ;
while [ expression ] ; do list ; done done | head
0
and 1
2
until [ expression ] ; do list ; done 3
4
The logic of the first reads: “While the expression evalu- 5
ates as true, execute the list of program statements. When 6
the expression evaluates as false, exit from the loop.” And 7
the second: “Until the expression evaluates as true, exe- 8
cute the list of program statements. When the expression 9
evaluates as true, exit from the loop.”
Now delete | head from the end of the program and run
While loop it again.
The while loop is used to execute a series of program state- In this version, the variable is incremented before its val-
ments while (so long as) the logical expression evaluates as ue is printed. This is specified by placing the ++ operator
true. Your PWD should still be ~/testdir. before the variable. Can you see the difference?
The simplest form of the while loop is one that runs for-
ever. The following form uses the true statement to always [student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((++X)) ;
generate a “true” return code. You could also use a simple done | head
“1”—and that would work just the same—but this illustrates 1
the use of the true statement: 2
3
[student@studentvm1 testdir]$ X=0 ; while [ true ] ; do echo 4
$X ; X=$((X+1)) ; done | head 5
0 6
1 7
2 8
3 9

An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com 17


Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

You have reduced two statements into a single one that It uses a logical comparison to count to a specific value:
prints the value of the variable and increments that value.
There is also a decrement operator, --. [student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ] ; do echo
You need a method for stopping the loop at a specific $((X++)) ; done
number. To accomplish that, change the true expression 0
to an actual numeric evaluation expression. Have the pro- 1
gram loop to 5 and stop. In the example code below, you 2
can see that -le is the logical numeric operator for “less 3
than or equal to.” This means: “So long as $X is less than 4
or equal to 5, the loop will continue. When $X increments to [student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ] ; do echo
6, the loop terminates.” $((++X)) ; done
1
[student@studentvm1 ~]$ X=0 ; while [ $X -le 5 ] ; do echo 2
$((X++)) ; done 3
0 4
1 5
2 [student@studentvm1 ~]$
3
4 Summary
5 This guide has explored many powerful tools for building
[student@studentvm1 ~]$ Bash command-line programs and shell scripts. But it
has barely scratched the surface on the many interesting
Until loop things you can do with Bash; the rest is up to you.
The until command is very much like the while command. I have discovered that the best way to learn Bash pro-
The difference is that it will continue to loop until the logical gramming is to do it. Find a simple project that requires
expression evaluates to “true.” Look at the simplest form of multiple Bash commands and make a CLI program out
this construct: of them. Sysadmins do many tasks that lend themselves
to CLI programming, so I am sure that you will easily find
[student@studentvm1 ~]$ X=0 ; until false ; do echo $((X++)) ; tasks to automate.
done | head Many years ago, despite being familiar with other shell
0 languages and Perl, I made the decision to use Bash for
1 all of my sysadmin automation tasks. I have discovered
2 that—sometimes with a bit of searching—I have been able
3 to use Bash to accomplish everything I need.
4
5 Links
6 [1] h
 ttp://www.both.org/?page_id=1183
7 [2] h ttps://www.apress.com/us/book/9781484237298
8
9
[student@studentvm1 ~]$

18 An introduction to programming with Bash . CC BY-SA 4.0 . Opensource.com

You might also like