These workstations run the Unix operating system. This document is designed to provide a quick introduction to the commands and concepts you will need to work under Unix.
Your view of the network will depend a great deal on the place where you are doing your work and the facilities provided there for connecting to the network. Some possibilities are:
You may also need to set you terminal's or program's communications parameters. Recommended settings are 8-bits and no parity. Use the highest speed supported by your terminal and modem. The ODU lines will automatically match speeds up to 14,400 baud.
If you are in the Southside Hampton Roads area you can dial in at 683-0001. From the Hampton Roads Peninsula, use 594-7790. These connect you to the ODU Computer Services. At the prompt cc-modem-gw4: You must enter the name of a machine on which you want to work. After entering a machine name, you should get the log-in prompt.
telnet machine-name.DEPT.odu.edu
where machine-name is a machine in your department and DEPT is your
abbreviated department name. Department names include:
setenv term xxxx
where xxxx is the kind of terminal (e.g., set term=vt100
). Some people also recommend that you follow this command with
tset -Q
which resets the terminal. In my own experience, this is usually unnecessary,and I have found that
many communications programs don't deal well with this, but try it if your terminal seems to be
misbehaving.
Most "dumb" terminals provide for 24 lines of text. Many communications programs, however, allow more. If yours is one of these, you should tell Unix how many lines you are using by giving the command
stty rows nn
where nn is the number of rows/lines.
yppasswd
This command will first prompt you for your old password (just to
check that you really are you!) and then will ask you to type your
new password (twice, so that an inadvertent typing mistake won't leave
you with a password that even you don't know!).
Whether we like it or not, we need to worry about the security of our computing environment. There are people who would take advantage of this computer system if they had any, or more complete, access to it. This could range from the use of computer resources they have no right to, to the willful destruction and/or appropriation of the information we all have online. In order to maintain the level of security in our computing environment that we need, there are some things we all have to take responsibility for. Even though you may not feel like you personally have much to lose if someone had access to your account or files, you have to realize that as soon as someone gains ANY access to our system, it's 100 times easier for them to gain access to ALL of it. So when you are lax with your own account, you are endangering the work and research of everyone else working here.
Your password is the fundamental element of security not only for your personal account, but for the whole UNIX system that we share. Without an account and password a person has NO access to our system. If someone discovers (or you tell someone) your password, not only will they have access to your personal files, but they will have a much better chance to launch attacks against the security of the entire system.
Your account password is the key to accessing and modifying all of your files. If another user discovers your password, he or she can delete all your files, modify important data, read your private correspondence, and send mail out in your name. You can lose much time and effort recovering from such an attack. If you practice the following suggestions, you can minimize the risk.
A person with local knowledge can also try your spouse's name, pets' names, etc. Your account is vulnerable to this type of cracking unless you choose your password carefully.
'/'
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
bin home usr
The bin directory contains many of the programs for performing common
Unix commands. The usr directory contains many of the data files that
are required by those and other commands. Of particular interest,
however, is the home directory, which contains all of the files
associated with individual users like you and me. Each individual
user gets a directory within home bearing their own login name. My
login name is zeil.
We can expand our view of the Unix files then as:
'/'
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
bin home usr...
/ | \ / \
/ | \ / \
/ | \ / \
cd ls ... zeil ...
It may be more precise to say that this directory's name is the empty
string "". cd and ls are two common Unix commands, as
will be explained later.Within my own home directory, I have a directory also named "bin", containing my own personal programs. Two of these are called "dgl" and "pcucp". So these files are arranged as:
'/'
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
/ | \
bin home usr...
/ | \ / \
/ | \ / \
/ | \ / \
cd ls ... zeil ...
|
|
bin
/ | \
/ | \
/ | \
dgl pcucp ...
The full name of any file is given by listing the entire path from the
root of the directory tree down to the file itself, with "/"
characters separating each directory from what follows. For example,
the full names of the four programs in the above diagram are:
/bin/cd
/bin/ls
/home/zeil/bin/dgl
/home/zeil/bin/pcucp
There are some common abbreviations that can be used to shorten file
names.
The command/program name is usually not given as a full file name. Instead, certain directories, such as /bin, are automatically searched for a program of the appropriate name. Thus, one can invoke the ls command as either
/bin/ls
or simply as
ls
As you type, some characters have a special meaning. For example, if
you have entered the first few letters of a file name and hit the
"Tab" key, the shell will examine what you have typed so far and
attempt to complete the filename by filling in the remaining
characters. If the shell is unable to complete the filename, a bell
or beep sound will be given. Even in this case, the shell will fill
in as many characters as it can.
Most special characters are entered by holding down the "Control" key
while typing a letter. By convention, we designate this by placing
the symbol "^" in front of the name of the second key. For example,
if you have typed zero or more letters of a filename and want to see a
list of what filenames begin with what you have typed, you could type
^D, i.e., hold down the "Control" key and type "d". Some other useful
special keys are:
Upon logging in, your working directory should be your home directory. The command pwd will print the working directory. Give the command
pwd
You should see something like
~yourname
Now, let's make a place to play in. mkdir will make a new directory.
Enter the command
mkdir playing
to create a directory named "playing".
The command ls lists the contents of the working directory. More
generally, ls directoryname will list the contents of any directory.
Give the command
ls
and you should see playing listed. In fact, it may be the only thing
listed. The command cd is used to change the working directory. Give
the command sequence
pwd
cd playing
pwd
cd ..
pwd
cd ./playing
pwd
to see this in action.
The cp command copies one or more files. You can give this command as cp file1 file2 to make a copy of file file1, the copy being named file2. Alternatively, you can copy one or more files into a directory by giving the command as
cp file1 file2 : :f:ilen directory
Now try the following:
ls ~public Notice that there are a number of files ending with ".txt".
cp ~public/*.txt ~/playing
ls ~/playing
The "*" is a wildcard character. It tells the shell to substitute any
combination of zero or more characters that results in an existing
filename. In cases where there are multiple possibilities, such as
this one, the shell forms a list of all the matches. So the cp
command actually saw a list of all files in the ~public directory
whose names ended in ".txt".
To get a better feel for wildcards, try the following:
ls /usr/include
ls /usr/include/*.* List only file names containing a ".".
ls /usr/include/f*.*
ls /usr/include/*f*.*
Here are some other common Unix commands. Try experimenting with
these in your ~/playing directory.
lpr -Pprinter file
You will need to consult your local staff to see what printers are
available at other sites.
man command
displays the manual page for the given command.
man -k keyword
looks up the given keyword in an index and lists the commands that may
be relevant.
emacs
Then follow the directions given to bring up the tutorial (i.e., type
^\ followed by "t".). When you are done with the tutorial, here are
few extra things you should know about emacs:
Most programs that run under X support a very simple "cut-and-paste" facility. Simply drag the mouse across a block of text in any window while holding down the left mouse button. Then position the mouse into a window where you would like that text to be "typed". Click the middle mouse button, and the selected text will be sent to that window just as if you had typed it yourself.
When emacs is run under X, this cut-and-paste feature is supported, but in a different fashion. Text that has been selected in another window by dragging the mouse can be retrieved in emacs by the command C-Y (^Y). Text that has been "killed" in emacs by C-K, C-W, or M-W can be inserted into other windows by clicking the middle mouse button.
NOTE: Some departments use the X Display Manager (XDM) as a
way to login, thus by passing the step of having to start X Windows.
5.0 Customizing Your Unix Environment
By now, you are probably tired of typing "setenv term..." and other
initial commands each time you log in. Now that you can edit files,
one of the first things to do is to customize your login procedure.
The shell uses two important files to customize behavior. When the shell is started up, it executes the commands in a file called ~/.tcshrc. Now, in a typical Unix session, you may actually be running many copies of the shell at the same time, perhaps without even being aware of it. The first time, however, that a shell is started because you have just logged in, it also executes the commands in a file called ~/.login. NOTE: If your department uses XDM then the .login is never used if you login on the console.
You may or may not already have versions of these files. You can check by giving the commands
cd ~
ls -a
If you don't have either of these, you should make one. If you do,
consider changing it as described here. First, let's create a .login
file. Enter emacs, and create a file with the following:
if ( "$TERM" == "vt100" __ "$TERM" == "network" ) then
set term=vt102
# tset -Q
endif
Instead of "vt102", you should enter whatever terminal type you use
most often. If you find that the tset command has been necessary for
you in the past, delete the # character. If you ususually reset the
number of lines with stty, add that command as well. Now your
terminal kind will be set automatically for you whenever you dial in.
If you would like to automatically run X whenever you are working at the console, add the following lines:
if ("`tty`" == "/dev/console") then
echo -n "Entering X windows (Control-C to interrupt)"
sleep 5
X
endif
NOTE: This is not needed for departments running XDM.
Be sure to enter everything exactly as shown above, including the quotes. Note that " is the double-quotation key, and that the ` characters around the word tty are the "backwards" apostrophe (You may need to hunt around on your keyboard to find this one, but it will not be on the same key as the ").
Now let's add a few useful items to the .tcshrc file. Edit your .tcshrc file and insert the following:
setenv EDITOR emacs
limit coredumpsize 0
# skip remaining setup if not an interactive shell
if ($?USER == 0 __ $?prompt == 0) exit
set history=40
set ignoreeof
set prompt="`hostname`: "
alias cp 'cp -i'
alias mv 'mv -i'
alias rm 'rm -i'
alias ls 'ls -F'
alias ff 'find . -name \!* -print'
The setenv line indicates that emacs is your editor of choice. Some
programs, including the mail program introduced in Section 6, will use
this information to load an editor when you have large amounts of text
to enter/alter.
Of the remaining lines, the most interesting are the alias commands. These set up "abbreviations" for commands. In this case, we are mainly adding options to familiar commands. The first three aliases add a -i option to the cp, mv, and rm commands. This option causes each command to prompt for a confirmation whenever its action would result in a file being deleted. The fourth alias adds the -F option to all ls commands, making it easier to tell the difference between ordinary files, directories, and executable programs. The final alias sets up a "find-file" command, ff. This will search the current directory and all subdirectories within it for a file matching a given pattern. For example the command sequence
cd ~
ff '*.txt'
will list all of your files with the .txt extension. After you have
checked these two files and saved them, you will have to log out and
then log back in again before they take effect.
There are several programs that you can use to get e-mail. I'll
describe the most basic of these, the Unix mail command here. Later,
you may want to check out the X-Windows mail tool, the mush program,
or the vm command for reading e-mail from within the emacs editor.
6.1 Sending
To send mail to someone with login name name, give the command
mail name
You will be prompted for a subject line to indicate what your message
is about. After that, you begin typing your message on the next
line. When you are done, type ^D on a line by itself. You will then be
prompted with "Cc:", which allows you to add the login names of other
people to whom you would like to send a copy of your message. (Many
people like to make a habit of cc'ing a copy to themselves.) If you
do not want to send any extra copies, just hit the "Return" key. Your
message will then be sent.
As you type your message, you can send special instructions to the mail program by entering any of the following at the start of a line:
To actually read your mail, give the command mail with no arguments. You should see a numbered list of your messages. If not, the command "h" (for headers) will list them. You can then read a message by typing it's number.
After reading the message, you can take any of several actions:
Exactly how you do this depends upon your usual access to the CCPO
network. You may need to try several approaches until you find one
that works well for you.
7.1 Transferring Files
7.1.1 At the console:
If you have physical access to a workstation with a floppy drive, you
may be able to transfer your files via 3.5" floppies. The floppies
must have been previously formatted on an IBM PC compatible machine,
for either 720k or 14.4k capacity.
Look for a workstation with a floppy disk drive (not all have them). The drive is known as 'a:/'. Insert your disk. The command mdir a:/ will display the top directory of the floppy disk contents. You can also specify individual directories via mdir a:/directory.
The command
mcopy unixfiles a:/directory
will copy one or more Unix files into the specified directory of the
floppy disk. directory may be omitted to copy into the top directory.
If, as is likely to be the case, all of the files being transferred
are text no executable programs or compressed files then add
the -t option:
mcopy -t unixfiles a:/directory
The mcopy command can also be used to copy from the floppy into the
Unix file system.
mcopy 'a:/file' unixdirectory
will copy a file from the floppy. If file includes wildcard
characters, multiple files will be copied. As before, if all the
files being transferred are text, then add the -t option.
mcopy -t 'a:/file' unixdirectory
Finally, please note that file names for the floppy disk should be
enclosed in apostrophes " (especially if they include wildcards).
Unix file names should not.
A command mdel is also available for deleting files on a floppy disk:
mdel 'a:/file'
ftp machine-name
where machine-name is the "full" Internet name of a Department
workstation. This full name is formed by taking the short name
(examples are given in Section 2.1.1) and adding
".DEPT.odu.edu", where DEPT is your department's abbreviated name.
You will then be prompted for your login name and your password. After entering those, your next commands should be
hash
binary
Now you can use the commands cd, pwd, and ls to navigate the Unix
directory structure as if you were in the shell. To get a file from
the Unix machine to your local machine, the command is
get filename
To put a file form your local machine onto the Unix machine, the
command is
put filename
Neither the get nor put commands can include wildcards in the
filename, but by changing the commands to mget and mput, you are
allowed to use wild cards.
To end your ftp session, the command is
quit
The most popular transfer protocols supported on the Department machines are called Kermit, Z-modem, Y-modem, and X-modem. If your communications software gives you a choice of these, you need to balance speed against robustness: the ability to cope with noisy telephone lines. Our personal impression is that in terms of speed, these should be rated, in order from fastest to slowest:
Z-modem, Y-modem, Kermit, X-modem
and in terms of robustness, from safest to least safe:
Kermit, Z-modem, Y-modem, X-modem
The popular MSKERMIT program offers a clean command that alters the
default settings of the Kermit protocol to make it nearly as fast as
Y-modem, at some cost in robustness.
Whatever protocol you choose, you will need to consult the documentation or help for your communications software to determine how to work it on your end of the connection. In this document all I can say is how to invoke the matching protocol on the Department end.
kermit -x
This runs kermit as a remote server, allowing you to immediately issue
get/send commands on your local Kermit.
rz
Then follow your software's procedure for sending files.To send files
from the Department to your machine using Z-modem, give the following
command to the Department machine:
sz file1...filen
Then follow your software's procedure for receiving files. On both
commands, if the files being transferred are all text (no executables
or compressed files), add a -a option immediately after the rz/sz
command name.
rx filename
Then follow your software's procedure for sending a file. To send
files from the Department to your machine using X-modem, give the
following command to the Department machine:
sx filename
Then follow your software's procedure for receiving files. Unlike the
other protocols, X-modem only allows transfer of a single file at one
time.
Some of the transfer methods outlines above will perform this conversion for you if you have told them that the files are text (which explains the -t and -a options recommended above).
If, however, you have transferred files to a Unix system and discover them to be full of ^ M characters (you can see this by viewing the file in emacs), you can use the command
dos2unix file1 file2
to produce a new file file2 from file1 by converting the line ends to
the Unix format.
On the other hand, if you have transferred files from a Unix system and find that the received files appear to consist of a single, extremely long line, you can use the command
unix2dos file1 file2
to get a new file file2 with ^M^J line terminators that can be
transferred to your non-Unix machine instead of the original file1 .
Finally please note that, although easily transferred files may
allow you to do most of the work of a programming assignment on your
home PC, do not fall into the trap of believing that you can simply
transfer the source code and submit it unchanged to your instructor
for grading on the Unix system. Different compilers for the same
language often allow a variety of non-standard language extensions (or
because of bugs, fail to properly compile standard language
constructs). Allow yourself ample time (at least a few days) to port
your code from one compiler to another.
8.0 Compilers
8.1 Compiling in the Shell
Now that you know how to create and edit files, you can generate new
programs. The most commonly used languages in the Department at the
moment are FORTRAN, C, and C++. The FORTRAN compiler is f77, and the
most popular C and C++ compilers are gcc and g++.
The simplest case for each compilers involves compiling a single-file program (or a program in which all files are combined by #include statements). For example, use emacs to prepare the following files:
hello.c
#include
int main ()
{
printf ("Hello from C!\n");
return 0;
}
hello.cc
#include
int main ()
{
cout << "Hello from C++ !" << endl;
return 0;
}
hello.f
PRINT*, 'Hello from FORTRAN'
END
The compiler generates an executable program called a.out. If you
don't like that name, you can use the mv command to rename it.
To compile files and run those programs, the commands are
gcc -g hello.c
a.out
g++ -g hello.cc
a.out
f77 -g hello.f
a.out
When you have a program consisting of multiple files to be compiled
separately, add a -c option to each compilation. This will cause the
compiler to generate a .o file instead of an executable. Then invoke
the compiler on all the .o files together without the -c to produce an
executable:
gcc -g -c file1.c
gcc -g -c file2.c
gcc -g -c file3.c
gcc -g file1.o file2.o file3.o
(Depending upon what else is in the same directory, the last command
can often be abbreviated to "gcc -g *.o".) The same procedure works
for the g++ and f77 compilers as well.
Another useful option in all three compilers is -D. If you add an option -Dname=value, then all occurrences of the identifier name in the program will be replaced by value. This can be useful as a way of customizing programs without editing them. If you use this option without a value, -Dname, then the compiler still notes that name has been "defined". This is useful in conjunction with compiler directive #ifdef, which causes certain code to be compiled only if a particular name is defined. For example, many programmers will insert debugging output into their code this way:
..
.
X := f(X, Y, Z);
#ifdef DEBUG
writeln ('*** X: ', X);
#endif
Y := g(X,Z);
..
.
The output statement in this code will be ignored by the compiler
unless the option -DDEBUG is included in the command line when the
compiler is run.
Get into emacs and call up one of the "hello" programs. Change it so that it contains one or more syntax errors, and save this file. Now give the emacs command: M-x compile.12 At the bottom of the screen, you will be asked for the compile command. If the suggested command is not what you want (it won't be, the first time you compile), then type in the proper command just as if you were typing it into the shell. emacs will invoke the compiler, showing its output in a window.
In this case, there should be one or more error messages. The
emacs command C-x ` will move you to the source code location of the
first error. Each subsequent use of C-x ` will move you to the next
error location in turn, until all the reported error messages have
been dealt with.13
8.3 Debugging
In the compilation commands given above, the -g option causes the
compiler to emit information useful for a run-time debugger. The
debugger of choice with these compilers is called gdb. The easiest
way to run gdb is, again, from inside emacs.
Try creating a longer program in the language of your choice, and compile it to produce an executable program a.out. From within emacs, look at one of the source code files for that program and then give the command M-x gdb.
At the prompt "Run gdb like this:", type the program name a.out. emacs will then launch gdb, and eventually you will get the prompt "(gdb)" in a window. You can now control gdb by typing commands into the gdb window. The most important commands are:
In addition to the above, the emacs command C-C < moves your view
of the code up the call stack, allowing you to see the caller of the
current procedure/function. The command C-C > moves you back down.
If you change to a window containing the source code and give the
command C-X space, a breakpoint will be set at the line of code where
the cursor is positioned.
9.0 More Shell Games
9.1 Redirection and Pipes
One of the interesting ideas that pervades Unix is that many, if not most, programs can be viewed as "filters" or "transforms" that take a stream of text as input and produce an altered stream of text as output. Many Unix commands are designed to perform relatively trivial tasks, perhaps not very useful by themselves, that can be chained together in interesting and useful ways.
The practical consequence of this is that Unix shells devote special attention to a standard input stream that forms the main input to most programs/commands, and to a standard output stream that forms the main output from most programs/commands. There is actually a second output stream supported by many programs, the standard error stream, used for writing error/debugging messages. The shell attempts to make it easy either to redirect one of these standard streams to a file or to pipe the standard output stream of one program into the standard input of another.
For example, the program wc (for word count) reads text from its input stream and produces as its output stream three number indicating the number of lines, words, and characters that it saw. You could invoke this directly:
wc
Hello.
How are you?
^D
in which case, you would see as output:
2 4 20
For this to be very useful, however, we need to make it accept a file
as input. This is done by using the < operator in the shell. Think of
the < as an arrow indicating data flowing towards the command from a
filename:
wc < hello.f
where hello.f is the file from Section 8.1, produces
the output
6 11 85
On the output end, the shell operator > directs the standard output
into a file (again, think of this as an arrow indicating data flowing
into a filename from the command):
wc < hello.f > hello.wc
produces no output on the screen, but creates a file called hello.wc.
That file will contain the output
6 11 85
of the wc command.
The output redirection operator has a couple of important variants.
First, the shell generally does not allow you to redirect into an
existing file. If you give the command
wc < hello.f > hello.wc
a second time, the shell will refuse to perform the command. You can
force the shell to delete an existing file and create a new one for
redirection by changing the > to >!.
Second, sometimes we would like to add output to the end of an
existing file instead of replacing that file. This is done with the
operator >>. So the code sequence
wc < hello.f >! hello.wc
wc < hello.f >> hello.wc
would result in a file hello.wc with contents
6 11 85
6 11 85
regardless of whether hello.wc had existed previously.
To pipe the output of one command into the input of another, use the shell operator |. A common example of a pipe is to take a command that may have a large amount of output and to pipe it through more to facilitate viewing. For example, try
ls /bin | more
As you gain facility with a greater variety of Unix text manipulation
commands, you will find that redirection and pipes can be a powerful
combination. For example, suppose that you have written program
myprog that emits a great deal of output, among which might be some
error messages starting with the phrase "ERROR:". If you wanted to
read only the error messages, you could, of course, just view all the
output, watching for the occasional error message:
myprog | more
But if the program produces a lot of output, this will quickly become
tedious. However, the program grep searches its input stream for a
given character string,16 emitting at its output only the lines
containing that string. By piping through grep, we can limit the
output to the part we really want to see:
myprog | grep "ERROR:" | more
Unix allows three forms of access to any file: read, write, and execute. For an ordinary file, if you have read (r) permission, you can use that file as input to any command/program. If you have write (w) permission, you can make changes to that file. If you have execute (x) permission, you can ask the shell to run that file as a program.
The owner of a file can decide to give any, all, or none of these permissions to each of three classes of people:
The ls -l command will show the permissions granted to each class. For example, if you said
ls -l ~/playing
you might see the response
total 315
- rwxrwx- -- 1 zeil 311296 Jul 21 09:17 a.out
- rw- rw- -- - 1 zeil 82 Jul 21 09:12 hello.c
- rw- rw- -- - 1 zeil 92 Jul 21 09:13 hello.cc
- rw- rw- -- - 1 zeil 85 Jul 20 15:27 hello.f
Look at the pattern of hyphens and letters at the left. The first
character will be a "d" if the file is a directory, "-" if it is not.
Obviously, none of these are directories. The next 3 positions
indicate the owner's (u) permissions. By default, you get read and
write permission for your own files, so each file has an "r" and a
"w". a.out is an executable program, so the compiler makes sure that
you get execute (x) permission on it. The other files can't be
executed, so they get no "x". This way the shell will not even try to
let you use hello.f or any of the other source code files as a
program.
The next three character positions indicate the group permissions. In this case, the group per- missions are the same as the owner's permissions.
The final three character positions indicate the permissions given to the world (others). Note that in this case, people other than the owner or members of the same group cannot read, write, or execute any of these files.
Directories also can get the same rwx permissions, though the meaning is slightly different. If you have read permission on a directory, you can see the list of files in the directory via ls or other commands. If you have execute permission on a directory, then you can use that directory inside a file name to get at the files it contains. So, if you have execute permission but not read permission on a directory, you can use those files in the directory whose names you already know, but you cannot look to see what other files are in there. If you have write permission on a directory, you can change the contents of that directory (i.e., you can add or delete files).
The chmod command changes the permissions on files. The general pattern is
chmod classpermissions files
Use "+" to add a permission, "-" to remove it. For example, chmod o+x
a.out gives everyone permission to execute a.out. chmod g-rwx hello.*
denies members of your group permission to do anything at all with the
"hello" program source code files.
myprog < test1.dat > test1.dat.out
myprog < test2.dat > test2.dat.out
myprog < test3.dat > test3.dat.out
myprog < test4.dat > test4.dat.out
myprog < test5.dat > test5.dat.out
Now, you can't execute dotest1, because you don't have execute
permission. (Do ls -l dotest1 to see this.) So use the
chmod command to add execute permission:
chmod u+x dotest1
Now you can execute dotest1 by simply typing
dotest1
Most shells provide special facilities for use in scripts. Since these
differ from one shell to another, it's a good idea to tell Unix which
shell to use when running the script. You do this by placing the
command #!/bin/csh in the first line of the script.
One such special feature is the use of the symbol $k to stand for the kth argument given to the script. For example, suppose that we wanted the ability to use a different set of test files each time we used the test script. One approach would be to create a script dotest2, as follows:
#!/bin/csh
myprog < $1 > $1.out
myprog < $2 > $2.out
myprog < $3 > $3.out
myprog < $4 > $4.out
myprog < $5 > $5.out
After the appropriate chmod, this could then be invoked as
dotest2 test1.dat test2.dat test3.dat test4.dat test5.dat
or with any other five test files. Of course, if we want to test with
only four files, or with six files, we're out of luck. It would be
nicer if we could have the script loop through as many files as we
list on the command line each time we run it. Such a script begins to
sound more like a program, and in fact most shells provide loops,
if's, and other programming language-like statements. Here, for
example, is the script dotest3 that will process each argument in
turn, however many there are:
In fact, you can list any program there, not just /bin/csh, and Unix will use that program to process the remainder of the lines in the script.
#!/bin/csh
foreach file ($*)
myprog < $file > $file.out
end
Here we use another special feature, the use of $ to indicate that we
want to retrieve a value from a variable, in this case the variable
file which is assigned by the foreach loop. Also, we use $*, which
denotes the entire list of arguments given to the script.
After the appropriate chmod, this script could then be invoked as
dotest3 test1.dat test2.dat test3.dat test4.dat test5.dat test6.dat
or perhaps as easily as
dotest3 test*.dat
Either way, the foreach statement will loop though all files named in
the argument list, setting file to each file name in turn.
The Unix program make is designed to simplify such project management. In a makefile, you record the steps necessary to build both the final file (e.g., your executable program) and each intermediate file (e.g., the .o files produced by compiling a single source code file).
We say that a file file1 depends upon a second file file2 if the file2 is used as input to some command used to produce file1.
When the make program is run, it then checks to be sure that all of the needed files exist, and that each needed file has been updated more recently than all of the files it depends upon. The key bits of information in a makefile, therefore are
Suppose that we are engaged in a project to produce 2 programs, progA and progB. progA is produced by compiling files utilities.c, progA1.cc, and progA2.cc and linking together the resulting .o files. Program progB is produced by compiling file utilities.c and progB1.f and linking together the resulting .o files. All of the .c and .cc files have #include statements for a file utilities.h. Also, both of the .cc files have an #include statement for a file progA1.h.
Here is a makefile for this project. This file should reside in the project directory, and should be called "Makefile" or "makefile".
# Macro definitions for "standard" language compilations
#
# First, define special compilation flags. These may change when
# we're done testing and debugging.
FLAGS=-g -DDEBUG
#
# The following is "boilerplate" to set up the standard compilation
# commands:
.SUFFIXES:
.SUFFIXES: .f .c .cc .h .o
.c.o: ; gcc $(FLAGS) -c $*.c
.cc.o: ; g++ $(FLAGS) -c $*.c
.f.o: ; f77 $(FLAGS) -c $*.f
#
# Targets:
#
progA: utilities.o progA1.o progA2.o
g++ $(FLAGS) utilities.o progA1.o progA2.o
mv a.out progA
progB: utilities.o progB1.o
f77 $(FLAGS) utilities.o progB1.o
mv a.out progB
utilities.o: utilities.c utilities.h
progA1.o: progA1.cc utilities.h progA1.h
progA2.o: progA2.cc utilities.h progA1.h
progB1.o: progB1.f
In the "SUFFIXES" area, standard commands are defined for producing a
.o file from a .c, .cc, or .f file. Of course these standard commands
simply invoke the C, C++, or FORTRAN compilers.
The key information is in the area labelled "Targets". Each target begins with a single line containing the name of the file to produce, a colon, and then a list of all files that serve as inputs to the commands that produce the file. Following that are any number of command lines that give the Unix commands to actually produce the file. Each command line starts with a "Tab" character (invisible in this listing). Command lines are not needed if the standard commands form the "Suffixes" area can be used to build the desired file.
Suppose that, with just this Makefile and the various source code files in your directory, you issued the command make progB. make reads the Makefile and notes that progB depends upon utilities.o and progB1.o. Since neither of these fiels exists, make sets out to create them. utilities.o depends upon utilities.c and utilities.h. Since these files exist and do not themselves depend upon anything else, make will issue the command to create utilities.o from them. This command is the "standard" command for making a .o file from a .c file:
gcc -g -DDEBUG -c utilities.c
Next make looks at progB1.o. It depends upon progB1.f which exists and does not depend upon
anything else. So make uses the standard command for FORTRAN files:
f77 -g -c progB1.f
Now that both .o files have been created, make proceeds to build its
main target, progB, using the command lines provided for that purpose:
f77 -g utilities.o progB1.o
mv a.out progB
and the progB program has been created.
Now suppose that we immediately give the command "make progA" (or just "make", since by default make builds the first target when none is explicitly given). Then the following commands would be performed:
g++ -g -DDEBUG -c progA1.cc
g++ -g -DDEBUG -c progA2.cc
g++ -g -DDEBUG utilities.o progA1.o progA2.o
mv a.out progA
Note that utilities.c is not recompiled, because make would notice that utilities.o already exists and was created more recently than the last time when either utilities.c or utilities.h was changed.
Now, creating a makefile may seem like a lot of trouble the first time that you want to compile your program. The payoff comes while you are testing and debugging, and find yourself making changes to two or three files and then needing to recompile. Which files do you really need to recompile? It can be hard to remember some times, and the resulting errors may be hard to understand. make eliminates this problem (as well as just being easier to type than a whole series of recompilation commands). This explains why, when you give the M-x compile command in emacs, the default compilation command is "make" rather than a direct use of any particular compiler.
When you prepare your own makefiles, you can re-use the first half
of the example above. You should only need to replace the targets. If
you want to test your makefile without actually performing the
commands, add a -n option to your command (e.g., make -n progB) and
make will simply list the commands it would issue without actually
doing any of them.
11.0 Where to Go From Here?
We've only scratched the surface in this document. There are many
more useful commands and programs available on the Department's Unix
machines, and many of the commands that we have covered have
additional options that have not been mentioned here. Remember that
you can use the Unix man command to call up documentation on any
command. The appendix lists a number of additional commands that you
may want to check out as you become more familiar with Unix.
12.0 Unix Command Summary
[]denotes options
{} denotes required argument
^ denotes control key (depress while typing listed letter).
... indicates that command has many options. Use man to learn
about this command.
awk ... a pattern matching and text manipulation language.
bg puts process in background after ^z
cal [month] {year} displays calendar for that month
cal displays calendar for current month
cat {filename} displays filename
cat [options]
-b number the lines, as -n, but omit
the line numbers from blank lines.
-n precede each line output with its
line number.
cd [directoryname] changes to directoryname, no argument
indicates home directory
cd .. changes to directory one above current
cp {file1} {file2} copy file1 naming it file2
mv {file1} {file2 or directoryname} move files or rename them
date displays date
diff {file1} {file2} compares two files, reporting any differences
echo repeats line; useful when using * and ?
in filenames
fg puts first command in background into
the foreground
grep {pattern} {filename} find pattern in filename
head -n Prints the first n lines of its input,
ignoring the rest
kill [option] {process id #} kill a process
-9 kill no matter what
exit exit (close) window or xterm
lpr {filename} send file to printer for printing
lprm {request} {userid} remove a file from the printer queue
lpq check status of printer and jobs
ls [options] list files
-l long form
-a all files, including .files
-g groups
mail see "man mail"
man [option] {command} display manual page for command
mesg {y or n} enable/disable messages to terminal
mkdir {directoryname} create a directory
more {filename} list filename one screen at a time
nroff,troff ... text formatting programs
ps show processes you are running
pwd print working directory
rm [option] {filename} remove files
-i interactive
-r recursive (use with caution)
rmdir {directoryname} remove directoryname
rwho who is on your current network
sed ... A non-interactive editor, useful for
writing scripts that involve string
replacements, line deletions, etc.
sort [options] {filename} sort filename
-b ignore spaces and tabs
-f sort upper- and lower-case together
-r reverse the sorting order
-o filename save the output of sort in filename
-t letter set field separator to letter
-u remove duplicate lines
ispell {filename} check spelling of filename
tail -n Prints the last n lines of its input,
tr Replaces/deletes characters
ignoring the rest
wc [options] {filename} count words, lines, and characters
-c characters only
-l number of lines only
-w number of words only
who who is running remote logins on your
machine
write {user} write message to user, ^d to
quit
yppasswd change password, follow prompts
? matches any single character in a
filename
* matches any number of characters in a
filename (or no characters)
& puts command in background when
appended to a command line
_ pipe, connects output of one command
with input of another
> redirects output of a command to a
file, erasing current contents
of a file
>> appends output of a command to an
existing file
< uses the file as an input for a command
^c aborts process (useful when "hung-up")
^d stops a process or signals "done"
on console, indicates logout