Programming tips and some time saving features of the bash shell
Lab 4
CSCI 112
Goals:
Learn some programming tips that will make
implementing the programs easier.
Learn some simple features of the bash shell that will save you lots of
time typing
Preventing files being
included multiple times
Consider the following files:
main.cpp
#include "bar.h"
#include "foo.h"
bar.h
#include "foo.h"
foo.h
class foo {...};
The preprocessor replaces each
#include
with the contents of the file being included. In this example,
when the file main.cpp is preprocessed, the contents of foo.h will
replace the #include "foo.h" in both main.cpp and bar.h. And the
#include "bar.h" in main.cpp will be replaced by the contents of
foo.h. The files generated by the preprocessor will look like
this:
bar.h
class foo {...}; // this came from replacing the #include "foo.h" with
the contents of foo.h
main.cpp
class foo {...}; // this came from expanding the #include "bar.h"
class foo{...}; // this came from expanding the #include "foo.h"
Now when main.cpp is compiled, there will be a compilation error
because class foo is multiply defined. The problem is that foo.h
was included multiple times.
You can prevent this problem by putting the following in EVERY .h file
you write (substitute the filename
of the current file for FOO):
#ifndef FOO_H // this
must
go on the first line of your file
#define FOO_H
contents of file
#endif // this must go on the last line of your file
How this works.
Many students have a hard time
understanding how the above mechanism works, and since it can be used
without understanding how it works, I'm not going to spend time
lecturing on how it works. I provide a brief description here for
those of you who are sill curious, and I will be happy to discuss how
it works anyone who is interested.
The directive ifndef stands for "if not defined." We can read the
above directives like this:
if the variable FOO_H is not
defined
this is the #ifndef FOO_H
{
define the variable
FOO_h
this is the #define FOO_H
rest of file goes here
}
this is the #endif
When the preprocessor starts to
process
a new .cpp file, there are no variables defined (its table of defined
variables is empty). Each time it encounters a #define directive,
it put that variable in its table.
The first time a .h file is read, the variable (by convention we use
FILENAME_H, for the file filename.h) associated with that file is not
in the table of defined variables, and thus the preprocessor enters the
body of the if-not-defined statement and reads everything in the file.
The next time that .h file is read, the variable associated with that
file IS in the table of defined variables and thus the preprocessor
goes to the end of the if-not-defined statement (that is, the #endif)
without reading everything in between.
The result is that the preprocessor will only ever read each .h file
once and you won't get multiply defined errors.
Incremental Programming
When learning to program in a new language, the
compiler
can provide the most help if you write your programs
incrementally. In other words, write a few lines of code and then
compile, and make sure your program works. If you have only
written a few lines of code, it will be much easier to figure out the
errors the compiler generated, and it will much easier to track down
logic errors.
Here is a game plan for writing program 2 incrementally:
- Create a makefile as describe in lab
3 or copy my Makefile.
- Create the Movie_db class files (movie_db.h
and movie_db.cpp). Make movie_db.cpp empty, and put an empty
class declaration in movie_db.h.
- Add the code described above to prevent multiple includes.
- Put in all the #include directives
(movie_db.cpp and main.cpp need to include
movie_db.h)
- Write a simple dummy main() function (I
usually just have my
dummy main print out "hello
world")
- Compile all 3 files. Fix all errors
until your program
prints out "hello world."
- Write the code in main.cpp to read in the
data. Write
temporary code to write out the data so you can be sure your program
reads the data correctly.
- Compile and test your program with several
different data sets,
fix all problems now.
- Write, compile, and test class
Movie_db
- Add code to main() to call Movie_db's
functions.
- You should be done at this point.
Programming incrementally will save you lots and lots of time even
though you have to write some code you eventually will delete (e.g.
printing hello words, and printing out the input from main
Making bash your default shell
On the department's computers,
bash is not the default shell.
The choice of shells is a matter of personal preference. bash is
currently one of the most popular shells, and is available on many
platforms including Windows (most varieties), Linux (all varieties),
UNIX (all varieties), OSX.
If you make bash your default shell, you can use the features described
below. Chances are that bash will work just like your current
shell, and you won't notice any difference, except that bash allows you
to use the features described below.
To make bash your default shell:
Log on to cougar using a
secure-shell (ssh) (note: ssh is similar to telnet but encrypts
your password so no one can steal it)
$ ssh
cougar.ecst.csuchico.edu
Now execute the command
chsh (change shell)
$ chsh
/bin/bash
It will ask you for your
password, and then change your shell.
After about an hour, every time you log onto a department machine, your
default shell will be bash.
This mechanism is broken. In
order to make bash your default shell you either have to go to Elbert
Chan's office hours or send him e-mail.
If you send him e-mail make sure you
tell him your ECST username.
In the mean time, you can start
the bash shell manually by typing:
$ /usr/bin/bash
bash profile
When bash starts, it executes the
file .bash_profile in your home directory (unless something is screwed
up
with your preferences, see below).
You can customize bash so it behaves the way you like it by putting
commands in .bash_profile. There is an example of such a command
below
in the section of command line editing.
Another thing you can add to .bash_profile is called an alias. An
alias is another name for a command. For example, if your 112
directory is:
~/classes/s06/112
to go to this directory you would have to type:
cd ~/classes/s06/112
if you do this a lot, you can create an alias in .bash_profile that
looks
like this
alias 112='cd ~/classes/s06/112'
now when you type 112 at the command prompt you will go to your 112
directory. I set up dozens of alias to make it easy to navigate
my file structure.
If your .bash_profile is not being executed automatically, the problem
is
probably with your windowing system settings. You can manually
run your .bash_profile by typing
$ source .bash_profile
Command history
bash keeps track of all the
commands you type in. You can see a list of your recent commands
using the history command
$ history
each command has a number:
...
401 cd lab6_files
402 ls -l
403 pico hello.cpp
...
you can execute one of the commands again by
typing ! followed by the number. For example,
$ !402
would be the same as typing "ls -l"
Command line editing
Commands in the command history
can also be edited
Use the up/down arrows to move up and down through the list, use the
left/right arrows to edit a command
For example, assume that the last command was "pico hello.cpp" if you
press up-arrow, "pico hello.cpp" will appear on the command line.
You can edit this to be "pico hello.h" by deleting the cpp and
inserting an h
If you are a vi or vim user, you can set the mode of command line
editing to use all the vi edit keys (e.g. i for insert, k for
up). Put the following in your .bash_profile (ONLY DO THIS IF YOU
ARE
A VI USER)
set -o vi
There is also an emacs command line edit mode (ONLY DO THIS IF YOU ARE
AN EMACS USER)
set -o emacs
File completion
bash has a feature to save typing
filenames. When you press the <tab> key, bash matches what
you have typed to all the files in the currently directory. For
example:
$ pico c<tab>
will automatically fill in
$ pico chart.cpp
IF chart.cpp is the only file in that directory that starts
with c. Assume there is another file that starts with c:
chart.h. then we
would get
$ pico chart.
and you would have to fill in the "h" or type "c<tab>" to get the
.cpp.
This is a real time savor, it is worth learning how to use.
More about shells
The bash shell (and other shells)
can do a whole lot more. There is an entire programming language
at your finger tips. I recommend you buy the O'Reilly book, Learning the bash shell to learn
more about bash.
Note: this book is also available on-line through the CSU Chico
Library: Learning
Bash (NOTE these links don't always work, you might have to
start at the Safari
search page)
Exercise 1:
Try the above bash features.
Exercise 2:
Work on program
2