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
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"
#!/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
What is the difference between an integer comparison and a string comparison? Give an example of when you would use each.
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.
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.
#!/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
Write a script same_head_and_tail.sh which checks whether the first and last lines of a file are the same.
#!/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
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"
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?
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