Home > Undergraduate > Open Source Tools and Scripting >    Labs

  CITS4407/CITS2003 OPEN SOURCE TOOLS AND SCRIPTING
 
 

Lab 4: Conditionals and Variables

In this lab, you will be writing more complex scripts. You must still ensure your syntax (the spelling of commands and placement of characters) is correct, but as labs progress you will need to pay more and more attention to the logic of your scripts (how the commands and control blocks interact). To help with this, try writing out the logic of your script in comments before adding shell commands or control blocks. For example, let's write a simple script that prints the third line of a file, if that file exists. Otherwise print an error message. The script will be executed as ./print_third.sh file.txt

#!/bin/bash

# get file name from command line

# check if file exists

# if file doesn't exist, print error message

# if file exists, print 3rd line

Ok, now let's add code

#!/bin/bash

# get file name from command line

# check if file exists
# if file doesn't exist, print error message
if [[ ! -f $1 ]]
then
    1>&2 echo ERROR
else
# if file exists, print 3rd line
    head -n 3 $1 | tail -n 1
fi

Some of these comments are a bit redundant, so we can tidy them up. In finished code, your comments should be brief explanations of why and how the code works. You shouldn't comment what every line is doing, but adding a comment to explain complex operations is totally fine.

#!/bin/bash

# check if file exists, if not print error message
if [[ ! -f $1 ]]
then
    1>&2 echo ERROR
else
    # if file exists, print 3rd line
    head -n 3 $1 | tail -n 1
fi

Planning your scripts this way not only helps avoid errors, it also helps other people to understand your script. The most important person who will have to read and understand your script is your future self. You might be very confident that you understand the script now, but in a few weeks time when you come back and read what you wrote you will be very thankful for clear and commented code!

Questions

  1. Modify print_third.sh so that it prints a different error if there is no input file (i.e. the first command line argument is an empty string). You can print to STDERR like this:
    1>&2 echo "THIS IS AN ERROR MESSAGE TO STDERR"
    
  2. #!/bin/bash
    
    # check if file exists, if not print error message
    if [[ -z $1 ]]
    then
        1>&2 echo "ERROR: No input file!"
        exit 2
    elif [[ ! -f $1 ]]
    then
        1>&2 echo "ERROR: File not found!"
        exit 1
    else
        # if file exists, print 3rd line
        head -n 3 $1 | tail -n 1
    fi
    
  3. What is the difference between an integer comparison and a string comparison? Give an example of when you would use each.
  4. Integer comparison compares the value of numbers numerically. You would use this when comparing lengths of strings or files. String comparison compares the characters in a string one by one. You would use this when checking if strings match or if a string is empty.
  5. Write a script find_longer.sh which accepts two files as command line arguments and prints the name of the longer file. If both files are equal, print "equal length". If an argument is missing or refers to a non-existent file, print an appropriate error message and set a nonzero exit status.
    Hint: you will want to use wc for this task, but wc filename.txt prints the file name as well as the counts. To prevent wc from printing the file name, you can pipe in the output of cat. For example, cat filename.txt | wc will not print the file name.
  6. #!/bin/bash
    
    # check both args are valid
    if [[ -z $1 ]] || [[ -z $2 ]]
    then
        1>&2 echo "Error: missing argument!"
        exit 2
    elif [[ ! -f $1 ]]
    then
        1>&2 echo "Error: could not find file $1"
        exit 1
    elif [[ ! -f $2 ]]
    then
        1>&2 echo "Error: could not find file $2"
        exit 1
    else
        # both files exist, so record their lengths
        first_len=$(cat $1 | wc -l)
        second_len=$(cat $2 | wc -l)
        if [[ $first_len -gt $second_len ]]
        then
            echo "$1 is longer"
        elif [[ $first_len -lt $second_len ]]
        then
            echo "$2 is longer"
        else
            echo "equal lengths"
        fi
    fi
    
  7. Write a script same_head_and_tail.sh which checks whether the first and last lines of a file are the same.
  8. #!/bin/bash
    
    # check if file exists, if not print error message
    if [[ -z $1 ]] || [[ ! -e $1 ]]
    then
        1>&2 echo ERROR
        exit 1
    fi
    
    # get first and last lines
    first=$(head -n1 $1)
    last=$(tail -n1 $1)
    
    if [[ $first == $last ]]
    then
        echo "First and last lines are the same"
    else
        echo "First and last lines differ"
    fi
    
  9. Modify your lab3 script sandwichsay so that users can pass an optional second command line argument to define how the bread should look. You may assume that the bread will only be a single line.
    ./sandwichsay "ham and cheese"
    
    %============================%
    ham and cheese
    %============================%
    
    ./sandwichsay "ham and cheese" "[++BREADBREADBREADBREAD++]"
    
    [++BREADBREADBREADBREAD++]
    ham and cheese
    [++BREADBREADBREADBREAD++]
    
    #!/bin/bash
    
    # check if user specified a bread
    if [[ ! -z $2 ]]
    then
        bread="$2"
    else
        bread="%============================%"
    fi
    
    echo "$bread"
    echo "$1"
    echo "$bread"
    
  10. You have decided that you want to run sandwichsay from anywhere on the system without having to specify its location (you want to just call sandwichsay not ~/wherever/sandwichsay). How could you do this?
  11. Add the location of sandwichsay to PATH. Adding somewhere like ~ to PATH is a bad idea, so you should put sandwichsay in a bin directory and then add that to your path (a good choice is ~/.local/bin).


Department of Computer Science & Software Engineering
The University of Western Australia
Last modified: 8 February 2022
Modified By: Daniel Smith

UWA