CP367: Lab 08 - Winter 2026 - Shell Programming II

Due 11:59 PM, Friday, March 13, 2026

Note: all examples in this lab use the #!/bin/bash she-bang as some of the operations are much more difficult to do in the default shell sh .

Arithmetic Expansion

Shell scripts normally treat variables as strings. However, strings that look like numbers can be easily used in arithmetic expressions. This is called arithmetic expansion. There are a number of methods of performing arithmetic expression, we shall look only at using double parantheses: var=((expression)) , as in the following script expand :

Script
#!/bin/bash
x=5
echo "x=5"
y=6
echo "y=6"
echo "Concatenation"
a=$x+$y
echo "\$x+\$y: $a"
echo "Addition"
b=$((x+y))
echo "\$((x+y)): $b"
echo "Comparison (<)"
c=$((x<y))
echo "\$((x<y)): $c"
echo "Comparison (>)"
d=$((x>y))
echo "\$((x>y)): $d"
exit 0

which results in:

Script Output
x=5
y=6
Concatenation
$x+$y: 5+6
Addition
$((x+y)): 11
Comparison (<)
$((x<y)): 1
Comparison (>)
$((x>y)): 0

Arithmetic expansion in scripts supports the typical operators: + , - , / , % , ++ , += , etc.


if

The if structure tests whether condition is 0 (the unix definition of success), and executes the commands within the appropriate code block. There are a wide number of tests available: comparisons, file tests, the results of arithmetic expressions, the exit status of commands, etc. The if may use one of the [...] or ((...)) conditions.

The if structure is:

				
if [ condition ] | (( condition ))
then
    ...
elif
then
    ...
else
    ...
fi

You may use multiple elif s and one else options. Both are optional.

if structures may be nested.

Integer Comparison Operators

The operators used differ depending on whether the conditions are tested inside square brackets [ ... ] or as arithmetic expansion within (( ... )) .

Comparison Operators
[ ... ] (( ... )) Purpose
-eq == equals
-ne != not equals
-gt > greater than
-ge >= greater than equal to
-lt < less than
-le <= less than equal to
-a && and
-o || or

Note: && and || do a short-circuit comparison, -a and -o do not.

String Comparison

Strings must be compared within square brackets [] .

The string comparison operators are == , != , < , and > , for their usual meanings. Strings are compared by their ASCII values, so case is significant.

Script
#!/bin/bash
echo -n "Enter your name: "

if [ $name == "David" ]
then
    echo "David!"
else
    echo "what?"
fi
exit 0

There are two further string comparison operations:

The following script checks for the existence of a 2nd argument to the script:

Script
#!/bin/bash
if [ -n "$2" ]
then
    echo "The 2nd argument is $2"
else
    echo "There is no 2nd argument"
fi
exit 0

Of course, a far better way to do this is to check whether the number of parameters is correct.

File Tests

The system provides a number of file tests - these are the most important ones:

File Tests
Operator Purpose
-e file exist (not in sh!)
-f file is a regular file - not a directory or device
-s file size is greater than zero
-d file is a directory
-r file has read permission
-w file has write permission
-x file has execute permission
-N file modified since it was last read
! not

Example: the script ftest takes a single file name as an argument and validates the file name with various file tests:

Script
#!/bin/bash
#if (( $# != 1 ))
if [ "$#" -ne "1" ]
then
  echo "Must have one filename as an argument"
  exit 1
elif [ ! -e "$1" ]
then
  echo "file $1 does not exist"
  exit 2
elif [ ! -f "$1" ]
then
  echo "file $1 is not a regular file"
  exit 3
elif [ ! -s "$1" ]
then
  echo "file has a size of 0"
  exit 4
elif [ ! -r "$1" ]
then
  echo "file lacks read permission"
  exit 5
fi
echo "File $1 is OK"
exit 0

case

The case structure allows you to evaluate a string against a number of options. Options are separated by double semi-colons ;; . The case structure is:

				
case "string" in
  "comparator_1")
    ...
    ;;
  "comparator_n")
    ...
    ;;
esac

The case structure is excellent for menus and validiting inputs and options.

The script say looks at its first argument and decides how to respond based upon that argument. Subsequent arguments are ignored.

Script
#!/bin/bash
case "$1" in
  "")    # No argument given.
    echo "So say something!"
  ;;
  "David"|"Professor"|"Sir")    # Multiple options.
    echo "Yes, can I help you?"
  ;;
  "Dave")    # I hate Dave.
    echo "You fail the course!"
  ;;
  *)    # This is a pattern.
    echo "Who are you talking to?"
  ;;
esac
exit 0

while

The while structure works much like a typical while you've seen in many languages. It may use either the [ ... ] or (( ... )) conditions. You may use multiple conditions within a while , but you must put all conditions within a single set of the brackets. The while structure is:

				
while [...] | ((...))
do
    ...
done

Example: The script key asks the user to enter a single character, evaluates it, then keeps asking until the user enters a ' * '.

Script
#!/bin/bash
# Testing ranges of characters.

echo "Hit a key, then hit return (* to exit)"
read KEY

while [ "$KEY" != "*" ]
do
  case "$KEY" in
    [a-z])
      echo "Lowercase letter";;
    [A-Z])
      echo "Uppercase letter";;
    [0-9])
      echo "Digit";;
    *)
      echo "Punctuation, whitespace, or other";;
  esac
  echo "Hit a key, then hit return (* to exit)"
  read KEY
done
exit 0

Example: The script sum asks the user to input a number from the keyboard and sum the values together.

Script
#!/bin/bash
SUM=0
echo "Enter a number (0 to stop): "
read N

while (( N > 0 ))
do
  SUM=$((SUM+N))
  echo "Enter a number (0 to stop): "
  read N
done

echo "Sum: $SUM"
exit 0

Note that this is an until with the same structure as a while , but its condition is a stop condition, rather than an continue condition.


for

The for loop is used to loop through a collection of elements as opposed to being a count-controlled loop, which is typically how a for is used in many languages. ( while loops can easily be used to loop a certain number of times.) The for structure is:

				
for element in collection
do
    ...
done

The seq n (sequence) command generates a list of numbers from 1 to n . This can be very useful in a for loop, as in the script seqtest :

Script
#!/bin/bash
if (($#==1))
then
    prod=1
    n=`seq "$1"`
    for i in $n
    do
        prod=$((prod*i))
        echo "$i : $prod"
    done
    echo "Product: $prod"
else
    echo "Must have 1 argument."
fi
exit 0

When executed with an integer argument, this produces:

Script Output
/home/dbrown/CP367> ./seqtest 5
1 : 1
2 : 2
3 : 6
4 : 24
5 : 120
Product: 120

The script args gives information about the arguments to a script and then displays the value of each argument using a for loop.

Script
#!/bin/bash
# Get the name of the script.
echo "The name of the script is in \$0"
echo "Name of script: $0"
echo
# Get the number of arguments to the script.
echo "The number of arguments passed is in \$#"
echo "Number of arguments: $#"
echo
echo "The arguments are stored in \$@"
echo "$@"
echo
# Display the actual arguments from within a loop.
echo "Looping through the variables:"
for arg in $@
do
  echo $arg
done
exit 0

Here is an example of executing args :

Script Output
/home/dbrown/CP367> ./args a b 1 2 Hello
The name of the script is in $0
Name of script: ./args

The number of arguments passed is in $#
Number of arguments: 5

The arguments are stored in $@
a b 1 2 Hello

Looping through the variables:
a
b
1
2
Hello

This final example shows how the commands used in earlier labs can be reused within a script. The wrap script calls sed (which in turn calls a sed script file) to wrap HTML code around the contents of the files whose names were given as arguments to the script.

Script
#!/bin/bash
for arg in "$@"
do
  echo "file $arg"
  if [ ! -e "$arg" ]
  then
    echo "$arg does not exist"
  else
    newfile=${arg}.htm
    `sed -f wraphtml.sed $arg > $newfile`
    echo "$arg was wrapped as $newfile"
  fi
done
exit 0
  1. Set up a small script calculator to ask the user for two numbers and add them together.


  2. Create a second version of your calculator to ask the user what operation to perform in +, -, *, /, and %.


  3. Create a third version of your calculator to loop until the user wants to stop.


  4. Create a fourth version of your calculator to store the inputs, operations, and outputs to a file (like a cash register tape).