Skip to content

Programming by Design

If you're not prepared to be wrong, you'll never come up with anything original. – Sir Ken Robinson

  • About
  • Java-PbD
  • C-PbD
  • ASM-PbD
  • Algorithms
  • Other

Ubuntu Topic 3 – Bash Shell Scripting

Posted on March 13, 2013July 27, 2015 By William Jojo
Uncategorized
Bash Shell Scripting

Note: This is not an exhaustive description of Bash. It barely qualifies as introductory. The amount of information on the Bash shell is extensive.

There is also an expectation that you have some basics of the command line. There is a wonderful, free bit of documentation in html and PDF form.

The Basics

Ubuntu uses the bash (Bourne Again Shell) as the user default shell. This is the shell the user is deposited into when they login. It is the shell that provides the prompt, accepts commands and then executes them on behalf of the user.

The shell, in addition to executing Linux/Unix commands on behalf of the logged-in user, has its own set of built-in commands. These commands are listed here. The SS64 web site is a good location for documentation as is TLDP (The Linux Documentation Project). There is also an advanced guide here.

Since the shell executes commands one at a time with each prompt, the next logical extension to that is the ability to create shell programs or scripts. Essentially, all of the shell built-in commands as well as the system commands can be arranged like a program. This is essential when there is a sequence of events that have to occur in a specified order or if there is a procedure that is done regularly. Turn the procedure into a script and then either run is manually when needed or automate the process with a program like cron.

Let’s start with some basics. The shell script needs to have a tag at the top to tell the active shell how to run the program. This tag appears as a comment since it starts with a hash (#), but also contains the program name that should be used to run all the statements that will follow. This special marker must be the first line and begin in the first column. An example is shown below.

[bash] #!/bin/bash

echo "Hello world!"
[/bash]

The script indicates that it should be run by the shell /bin/bash. Let’s say we save those lines of code into a file called hello. You run a script simply by typing its name at a shell prompt.

$ hello

When running scripts, they must have execute permissions. If you try to run a script and get a Permission denied error, there’s a good chance the execute permission is not set. This is easily remedied with:

$ chmod u+x hello

Further if you run the command, but instead of permission denied, you get command not found for an error, then you do not have the current directory (.) in your search path. To get around this, you can edit your PATH environment variable (discussed later) or simply alter the way you run the script.

$ ./hello

Variables

Assigning

Variables are simple identifiers of string data. Integer types can also be used, but basically everything is a string. Values are assigned using an equals sign (=) with no spaces in between.

[bash]var=value[/bash]

OR

[bash]var="value with spaces"[/bash]

OR

[bash]var=’value with spaces'[/bash]

OR

[bash]var=value\ with\ spaces[/bash]

There are different kinds of quotes which will be discussed below.

Accessing

Accessing the values of variables is done with the dollar sign ($) dereference operator.

[bash] var="value with spaces"
echo $var
[/bash]

Concatenating

We can combine strings simply by placing them close together as shown in the next example

[bash] #!/bin/bash

var1=abc
var2=123
var3=xyz

echo -e "var1 = $var1\nvar2 = $var2\nvar3 = $var3"

var4=$var1$var2$var3
echo "var4 = $var4"
[/bash]

The -e option of echo simply tells echo to process the \n as a newline instead of literal text. The value of var4 is made by concatenating the values of var1, var2 and var3.

When using the dereference operator in conjunction with concatenation, you have to be careful of mixing. Consider the following:

[bash] v=play
echo $ving
[/bash]

The author wanted to add ing to the end of the value of v. The shell interpreter read that line as accessing the variable ving which has no value. Therefore nothing would be displayed except a blank line.

To fix this we use braces ({}) to separate the variable from the string literal to be concatenated.

[bash] v=play
echo ${v}ing
[/bash]

Quotes

You may not realize it, but you’ve seen some details above regarding quoting that were not specifically pointed out.

Back Quotes or Back Ticks

These characters allow you to call a command and have the results returned as a string to be assigned to a variable or used as an argument to another command. Consider the following:

[bash] today=`date +’%y%m%d’`
echo $today
[/bash]

The use of this kind of quoting has been deprecated and the use of $() should be used instead.

[bash] today=$(date +’%y%m%d’)
echo $today
[/bash]

The old method only shown here in the event you should run into old scripts that use it.

Escape Character (Backslash)

The use of the escape character or blackslash (\) is to change the default behavior of a single character. Consider the following:

[bash] echo "That will be $22"
[/bash]

The output would be

That will be 2

This is because the dollar sign is the variable access operator and $2 means the second argument passed to this program – which we haven’t discussed yet, but that’s what it is.

To fix this we need to have the dollar sign mean just a dollar sign. The escape character is one way to solve this.

[bash] echo "That will be \$22"
[/bash]

Another way to solve this is to read on.

Single Quotes

As we have already seen, variable expansion (using the $ operator) and more will happen inside of double quotes. To keep any of those things from happening and to treat every character as simply a character to be displayed as-is we use single quotes.

[bash] echo ‘That will be $22’

echo ‘$var is not expanded and I can call $(somecommand) without anything happening.’
[/bash]

Double Quotes

When using double quotes, everything is printed as-is except $, ` and \. That is, the dollar sign, back tick and backslash retain their special properties as previously explained. So that means that:

[bash] var=text
echo "\$var = $var and `date +’%y%m%d’` = $(date +’%y%m%d’)"
[/bash]

Produces:

$var = text and 130312 = 130312

Tests

Truth in shell scripting is based on the return value of commands. A return value of zero (0) indicates success and non-zero means something else happened. Hence, zero mean true and non-zero means false.

There are three forms of testing. They help our programs react through conditional processing and grant us the ability to examine a variety of details.

test and [ ]

The test built-in command and the [ ] operator are identical. They both offer a list of file testing options:

Unary operators
-d	Is a directory
-e	File exists
-f	Is a regular file
-h	Is a symbolic link (also -L)
-r	Is readable by you
-w	Is writable by you
-x	Is executable by you 
-s	Is not empty

Binary operators
-nt	Test if file1 is newer than file 2 based on modification date
-ot	Test if file1 is older than file 2 based on modification date
-ef	Test if file1 is a hard link to file2.

The test built-in can also do arithmetic comparisons:

-eq	Is equal
-ne	Is not equal
-lt	Is less than
-gt	Is greater than
-le	Is less than or equal
-ge	Is greater than or equal

string comparisons

Binary operators
=	Is equal (also ==)
!=	Is not equal
<	Is less than
>	Is greater than

[Note: < and > need to be escaped when using [] since they also represent the redirection operators]

Unary operators
-n	String has a non-zero length
-z	String has a zero length

and logical operators

-o	Logical or
-a	Logical and

[[ ]]

This test construct is very similar to the [ ] version. However, filename expansion and word slitting are not processed.

All other aspects are the same and you also gain the ability to use &&, ||, < and > more freely.

(( ))

This is the test to perform arithmetic expressions. It also has the ability to use the C-style increment (++) and decrement (--) operators. The comparison operators are more rich:

=	Is equal (also ==)
!=	Is not equal
<	Is less than
>	Is greater than
<=	Is less than or equal
>=	Is greater than or equal

Conditionals

Now that we've seen the tests, we should put them to good use. The basic structure of it test is

if condition; then
  statements
fi

OR

if condition
then
  statements
fi

OR

if condition; then
  statements
else
  statements
fi

OR

if condition; then
  statements
elif condition; then
  statements
else
  statements
fi

OR

if condition; then
  statements
else
  if condition; then
    statements
  else
    statements
  fi
fi

As you can see there are several variations to how the if can actually be constructed.
Here is a script with some standard if-elif-else tests to show both how to construct an if-test and how to use the tests.


Loops

while

The while loop is a top test loop and is written in the form:

while condition; do
  statements
done

OR

while condition
do
  statements
done

The following will use an integer variable x to print the values 0 through 9:

[bash] #!/bin/bash

let x=0

while (( x < 10 ))
do
echo $x
(( x++ ))
done
[/bash]

for

The for loop uses lists of strings separated by spaces (quotes are honored) to denote a list. Let's say you wanted to generate some IP addresses in a particular range. Let's say further that we wanted to generate hundreds of insert statements suitable for a simple MySQL table. We could use two loops - one for and one while in the following manner:

[bash] #!/bin/bash

for x in 248 249
do
let y=2
while (( y < 255 ))
do
echo "insert into ip_list values('192.168.$x.$y');"
(( y++ ))
done
done
[/bash]

The above example may raise the question on the further use of quotes. Such as, why are $x and $y evaluated within single quotes? The answer is the outer (double) quotes are what matter here. The inner (single) quotes are simply displayed literally as no further quotation processing is done once the outer set has begun. Therefore variable expansion will happen even within the nested set of single quotes.


Here Documents


Command line arguments


Functions

Post navigation

❮ Previous Post: CISS-111 Extra Credit GUI
Next Post: CISS-111 Project 6 ❯

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Copyright © 2018 – 2025 Programming by Design.