![]()
![]()
COMP2100
Lab 1: Shell programmingSummary
You will get some experience interacting with the shell and writing some simple bash scripts.
Aims
Develop familiarity with Unix command-line interaction.
Get some experience writing simple shell scripts.
Become familiar with the style and conventions which are very different from those of Eiffel.
Witness the power of simple scripts to automate otherwise time-consuming operations.
Preparation
Read through your notes for Lecture 4.
Do Homework 1.
Exercise 1
Get a terminal window up on your screen and enter the following command:
echo Hello worldYou should see the response Hello world appear as a result.
That command was interpreted by tcsh, your default shell. For these exercises we want to use the bash shell. To start bash just enter the command bash. When you do this, the prompt will change to something ending with a $ -- this is the default prompt for all shells in the Bourne shell family.
Enter the command to print `Hello world' again, this time to bash. You should get the same result. One shell is pretty much like another when processing simple commands.
You can exit bash either by typing the command exit, or by typing Ctrl-D (hold down the Control key and press d). In UNIX, Ctrl-D signals the end of input to a program with which you are interacting.
Exercise 2
Create a directory called bin in your home directory (if you don't already have one). This directory is one place your shell will go looking for commands that are not built in to the shell. If you write a program of your own that you want to use on a regular basis, just copy it to this directory. Then, whenever you type the name of your program as a command, the shell will find it here and run it. (For a complete list of all the places the shell will look, known as a `search path', enter the command echo ${PATH}.
Create a file called hello in your bin directory with the following contents:
#!/bin/bash echo Hello worldNext set the executable bit on this file with the command chmod +x hello.
You should now be able to run your new command by typing its name ./hello. You don't have to be in the same directory as your command for this to work. Try moving to another directory and typing hello again.
Exercise 3
Make a new directory (say comp2100/labs/lab1) and download the following Eiffel program strcnt.e into it. The main routine is called main. Compile the program by typing
compile -o strcnt strcnt mainWhen run, this program accepts two string arguments and returns a count of how many times the first string can be found in the second. Occurrences must be contiguous, for example, `cat' does not occur in `cxaxt'. Occurrences may overlap, for example `wowow' occurs twice in `wowowow'.
Well, that's what it's supposed to do. In reality, it doesn't come close to working. Try it out by typing
./strcnt abc abcdYou should get the answer `1', but you won't.
It's going to take a long time to test this program if we have to enter each test case by hand, and re-enter it by hand after every modification. Chances are we'll end up making as many mistakes as the program. Instead, let's write a shell script to do it. Start by creating a file called cases to contain your test cases. Each line should contain two strings. Here are a few lines to get you started. Add some more of your own.
x x x xx wowow wowowowowThe following simple shell script will read two words from each line of input and print those words out again.
#!/bin/bash while read x y do echo ${x} ${y} doneThe key feature of the script is the read command, which we didn't cover in lectures. It reads a line of input and assigns the first word to the variable x and the rest of the line to the variable y. The read command gives an exit code of 0 (= success = True) if was was able to read the words, or 1 (= failure = False) if it encounters the end of its input.
Save this script in file called tester, make it executable, and run it over your test input by typing ./tester < cases.
Hint: When editing shell scripts you may find it helpful to put Emacs into `shell-script-mode'. If you edit an existing script, this should happen all by itself, but when you start a new script you need to tell Emacs to change mode by typing M-x shell-script-mode. (The M stands for `Meta', and it works just like Shift or Control: hold down the Alt key while you type an `x'.)
Exercise 4
Modify tester so that for each input line of the form `string1 string2', it outputs the number of occurrences of string1 that strcnt claims are in string2.
Note: This does not mean rewrite the Eiffel program as a bash script. It means write a bash script which runs the Eiffel program on each line of its input and formats the results.
Exercise 5
Save the current version of your script and your cases file for later. (You will need these again in Exercises 8 and 9.) Do this by copying tester to tmp_tester and cases to tmp_cases using the cp command.
Modify your cases file so that each line now contains 3 things, the two words as before, plus the correct number of occurrences of the first word in the second. For example, your file will start:
x x 1 x xx 2 wowow wowowowow 3Modify your tester script so that for each test it prints a line of the following form:
Test i: string1 string2: Expected n, got mwhere i is the line number of this test, n is the correct number of occurrences of string1 in string2, and m is the number found by strcnt.
Exercise 6
Modify your tester so that when strcnt actually gets the right answer (a rare occurrence, but you should be able to find one), then it instead prints a line of form:
test i: PassedThe key to this (unsurprisingly) is to use an if statement in your shell script. Remember that the form of an if statement is as follows:
if command-list then command-list else command-list fiNote: The line breaks (or ;s in their place) are required. You can leave out the else part if you don't need it.
Have a look at the manual page for the test command (by typing man test). That should tell you everything you need to know now to complete this exercise.
Exercise 7
The test command is so commonly used in shell scripts that bash has introduced a short-hand notation in which [ stuff ] means the same as test stuff (those spaces are required). Use this notation to simplify your solution to Exercise 6.
Exercise 8
For this exercise you should return to using a version of your test cases file where each line just contains the two strings to be tested. Make a second file called expected that contains just the correct answers for your test cases, one per line. Now, create a new tester script that writes the output from each of your tests to a file called results.
Hint 1: The line command > file redirects the output of command into file. Similarly, command >> file appends the output of command to the existing content of file (creating it if it did not previously exist).
Hint 2:: You may wish to solve this problem by first removing the file results and then adding output to it one line at a time. Check out the manual entry for options to rm that will cause the command to work cleanly even when the file to be removed does not exist.
Exercise 9
Create another version of the tester script that works like the one from Exercise 8, but then uses diff to check if the results produced are the same as the expected answers. If yes, have your script print `All tests passed', otherwise have it print `Some tests failed'.
Hint: Output redirected to the special file /dev/null will neither be seen nor heard from again.
Exercise 10
How many Eiffel class files do you have in your file space?
Hint 1: Commands can tell if their output has been redirected to a file or a pipe, and can change their behaviour as result. Check out the difference between the output of ls and ls | cat. The cat command just copies its input to its output, so any differences have come about because ls sensed it was connected to a pipe and modified its behaviour. Why would it do that?
Hint 2: You should be able to answer this by using only the commands ls, wc, and grep.
Hint 3: Check out the -R option on ls and all the options on wc. (Use the man command.)
Hint 4: The grep pattern '\.e$' (those quote marks are important) will match lines ending in .e.
Exercise 11*
Starred exercises are extension work, and should not be attempted until you have solved all the regular exercises. They are optional, but remember that the more you do, the more you will learn.
So, where are all these Eiffel files then? Just using ls and grep can get you the names of all your Eiffel files, but it won't tell you where to find them. Read the manual page for the find command, and then use it to print the locations of all your Eiffel files.
Exercise 12*
Fix the strcnt program and check your fixes by using the testing script and test data you developed earlier.
![]()
![]()
Copyright © 2004, Jim Grundy & Ian Barnes, The Australian National University
Feedback & Queries to
comp2100@iwaki.anu.edu.au
Version 2004.1, 29 February 2004, 15:09:09