A Much-Too-Terse Introduction to Unix

Dr. Steven J. Zeil and Joe Gazala, both from ODU CS


Tabel of Contents

  1. Working on a Unix Network
  2. The Basics
      2.1 Logging In
        2.1.1 Making a Connection
        2.1.2 Logging In
        2.1.3 Setting Your Terminal Type
        2.1.4 Changing Your Password
      2.2 The Unix File System
      2.3 Shell Games: Typing Unix Commands
      2.4 Some Basic Unix Commands
      2.5 Getting Help
  3. Editing Text Files
  4. X Windows
  5. Customizing Your Unix Environment
  6. Using Electronic Mail
      6.1 Sending
      6.2 Receiving
  7. File Transfer
      7.1 Transferring Files
        7.1.1 At the console
        7.1.2 Internet
        7.1.3 Dialing in
      7.2 Problems and Inconsistencies
  8. Compilers
      8.1 Compiling in the Shell
      8.2 Compiling in emacs
      8.3 Debugging
  9. More Shell Games
      9.1 Redirection and Pipes
      9.2 File Protection
      9.3 Scripts
  10. Project Management with Make
  11. Where to Go From Here?
  12. Unix Command Summary

Working a on Unix Network

This Department maintains a large network of Sun workstations for teaching and research.

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:

2.0 The Basics

2.1 Logging In

2.1.1 Making A Connection

You should receive, from your instructor or from the local systems staff, a log-in name and a password. The first thing you must do is to get a log-in prompt from a machine. How you do so depends upon your access mode:

2.1.2 Logging In

Now that you have a login prompt, enter your login name. At the "password:" prompt, enter your password.

2.1.3 Setting Your Terminal Type

If you are at the console, you may skip this Section. If you are dialing in or connecting via the Internet telnet program, you must now tell the Unix workstation what kind of terminal you are using. The command to do so is:
      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.

2.1.4 Changing Your Password

The command to change your password is
      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.

  1. NEVER give another user your password. There is no reason to do this. You can change permissions and have groups set up if you need to share access with other individuals. Your account should be yours alone.
  2. Never write down your password. Another person can read it from your blotter, calendar, etc. as easily as you can.
  3. Never use passwords that can be easily guessed. Personal information about you (birth date, etc.) may be known to the attacker or may be recorded in on-line databases that the attacker has already obtained.
  4. Passwords should not be single words (in any language) because on-line dictionaries are widely available for use in spelling checkers. A common approach to cracking passwords is to compile a set of words (such as those in the UNIX dictionary) and to run a program that tries each one on each account on the machine. Consider inserting punctuation and other "odd" characters into your password to foil such attacks.

    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.

  5. Change your password the very first time you log in, and every few months thereafter. Security problems are often traceable to stale passwords and accounts. These are accounts that have become inactive for one reason or another or the password has not changed for a long time. In our particular environment we have had break-ins via such stale accounts. A password that remains the same for a long time provides an intruder the opportunity to run much more advanced and longer running programs to break such passwords.
  6. Vary the system by which you choose a password. For example, don't repeatedly use combinations like BLUEgreen and REDyellow. If an intruder discovers your pattern, he or she can guess future passwords.

2.2 The Unix File System

Files in Unix are organized by listing them in directories. Directories are themselves files, and so may appear within other directories. The result is a tree-like hierarchy. At the root of this tree is a directory known simply as "/".2 This directory lists various others:
			     '/'
			   /  | \ 
                          /   |	 \
			 /    |	   \
			/     |	    \
		       /      |	     \
		      /       |	      \
		     /        |	       \    
		    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. Unix filenames can be almost any length and may contain almost any characters. As a practical matter, however, you should avoid using punctuation characters other than the hyphen, the underscore, and the period. Also, avoid blanks, and non-printable characters within file names. All of these have special meanings when you are typing commands and so would be very hard to enter within a filename.
Some things to keep in mind about Unix file names that may be different from other file systems you have used:

2.3 Shell Games: Typing Unix Commands

To run a Unix command (or any program, for that matter), you normally must type the name of the command/program file followed by any arguments. There is actually a program running that accepts your keystrokes and launches the appropriate program. The program that reads and interprets your keystrokes is called the shell. There are many shells available, all of which offer different features. The default shell is called tcsh, and we'll concentrate on that.

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:

2.4 Some Basic Unix Commands

If you have not yet done so, log in now so that you can work though the following commands.

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.
cat file1...filen
Lists the contents of each of the listed files on your screen.
exit
Shut down the current shell. If this shell is the one you got at log-in, this command logs you out.
mv file1 file2
Renames file1 as file2 . file2 may be in a different directory.
mv file1 directory
Moves file1 to the given directory.
lpr file
Send file to printer for printing. Most sites have multiple printers, each having its own name. One of these will be the "default" printer used by the lpr command. For the others, you must give the printer name as part of the printer command:
             lpr  -Pprinter  file
You will need to consult your local staff to see what printers are available at other sites.
lpq
Shows the list of files "queued up" awaiting their turn on the printer. As with lpr, you can specify a particular printer by name as lpq -Pprinter.
lprm request
Remove a file from the printer queue. The request number is found using the lpq command. To specify the particular printer, use lprm -Pprinter request.
ls -a
By default, filenames beginning with "." are considered "hidden" and not shown by the ls command. The -a (for "all") option causes these files to be shown as well.
ls -l
This is the "long" form of ls. It displays additional information about each file, such as the size and date on which the file was last modified. Note that options can be combined. For example, you can say ls -la to get extra information including normally hidden files.
ls -F
Adds a little bit of extra information to each file name. If the file is an executable program, its name is marked with an "*". If the file is a directory, its name is marked with "/".
more file1...filen
Lists files one screen at a time, pausing after each screenfull. Hit the space bar to advance to the next screen. A related program is less, which also allows you to move backwards through the files by hitting "b".
rloginmachine
Logs you in to another machine on the network. Use this if the machine you are on seems to be running slowly and the who command indicates that there are lots of others on the same machine.
rm file1...filen
Deletes the listed files. Be very careful using wildcards with this command. rm * will delete everything in the current working directory!
rm -i file1...filen
Deletes the listed files, but firsts asks permission to delete each one.
rm -r file1...filen
Deletes the listed files. If any of these files is a directory, it deletes that directory and everything in it as well.
rmdir directory
Deletes a directory.
who
Lists everyone logged into the same machine that you are using.

2.5 Getting Help

As you explore Unix, you are bound to have questions. Some ways to get answers include:

3.0 Editing Text Files

An editor is a program that allows you to easily create and alter text files. There are a variety of editors on the system, of which the most popular are vi and emacs. Neither is exactly the easiest thing in the world to learn to use. We suggest learning emacs, because To run emacs, make sure that you have correctly identified your terminal kind (see Section 2.1.1). Then give the command
      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: For more information on either emacs or vi you can click on the following:

4.0 X Windows

If you are working at the console, you can take advantage of the X windowing system. By running X, you can have several windows on the screen open at once, each devoted to a different task. For example, you can be reading electronic mail in one window while a lengthy compilation is running in another. X also allows the display of graphics and of a variety of fonts,

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.

6.0 Using Electronic Mail

Electronic mail, or "e-mail", for short, is an important part of the ODU Unix environment. Besides being a useful way to exchange personal messages, e-mail is used by the Department for official announcements. Many instructors distribute grades by e-mail. They may send hints and corrections for projects and assignments that way, or distribute special files needed by all students in the class. E-mail may be the best way to pose a short question to your instructor outside of class, since you don't actually need to catch your instructor in person at a time when he/she's not busy with someone else.

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:

~e
Enter the editor named by the EDITOR environment variable ( see Section 5). This is a good way to correct mistakes made on previous lines.
~r filename
Insert the contents of a file into your mail message.
~p
Print the message as it appears so far.
~m #
If you are actually replying to a mail message that you received (see Receiving, below), this inserts the text of mail message number # into your reply.

6.2 Receiving

When you first log in, you will be informed if you have received e-mail. At that time, or anytime thereafter, you can use the frm command to list the messages awaiting.

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:

r
Send a reply to the author of the message you just read.
R
Send a reply to the author of the message you just read and to anyone in the Cc: list of that first message.
dp
Delete this message and move on to the next (if any).
n
Move on to the next message.
s filename
Save a copy of this message in the specified file. If the file already exists, the message is added to the end.

7.0 File Transfer

If you prepare files on one machine but want to use them on another, you need some means of transferring them. For example, if you edit files on your home PC or on a PC at one of the Teletechnet sites, you will eventually need to get those files onto the Department network. On the other hand, you may want to take files your instructor has provided off of that network for use on your home PC.

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'

7.1.2 Internet

If you are on a machine that has an Internet connection, you can transfer files to other such machines using the ftp program. This would be the menas of choice, for example, for exchanging files between the laboratories at the Peninsula Graduate Center and the main Norfolk campus. Give the command
      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

7.1.3 Dialing In

If you are dialed in to a Department machine, you use a transfer protocol to send/receive files. Which protocol you use depends upon what your particular communications program supports. Most such programs have one or more protocols built in, or allow a separate protocol program to be run while still dialed in.

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.

7.2 Problems and Inconsistencies

One fact that you should keep in mind is that Unix systems and many home computer systems do not represent lines in text files in the same way. Unix terminates each line in a text file with a line feed character (^J). MSDOS and some other operating systems terminate lines in text files with a two character sequence consisting of a carriage return (^M) followed by a line feed (^J).

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.

8.2 Compiling in emacs

When your programs contain mistakes, compiling them in the shell can result in large numbers of error messages scrolling by faster than you can read them. For this reason, I find it best to compile from within the emacs editor.

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:

set args...
If your program expects arguments on its command lane when it is invoked from the shell, list those arguments in this command before running the program.
break function
Sets a breakpoint at the entry to the named function (i.e., indicates that you want execution to pause upon entry to that function).
run
Starts the program running.
c
Continues execution after it has been paused at a breakpoint.
n
Executes the next statement, then pauses execution. If that statement is a function/procedure call, the entire call is performed before pausing. You can also do this by giving the emacs command C-C C-N.
s
Like n, executes the next statement, but if that statement is a function procedure call, this com- mands steps into the body of the function/procedure and pauses there. You can also do this by giving the emacs command C-C C-S.
p expression
Prints the value of expression, which may include any variables that are visible at the current execution location.
quit
Ends your gdb session.

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

9.2 File Protection

Not every file on the system should be readable by everyone. Likewise, some files that everyone needs (such as the executables for commands like cp, mv, etc.) should not be subject to accidental deletion or alteration by ordinary users. This is where file protection comes into play.

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:

These three classes are abbreviated "u", "g", and "o", respectively. The "u" is for "user", "g" for "group", and "o" is for "others". Until you actually join a project that needs its own group, you will mainly be concerned with "u" and "o" classes.

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.

9.3 Scripts

You can put any sequence of Unix commands into a file and turn that file into a command. Such a file is called a script. For example, suppose that you are working on a program myprog and have several files of test data that you run through it each time you make a change. Create a file dotest1 with the following lines:
      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.

10.0 Project Management with Make

When you begin to develop projects that involve multiple files that need to be compiled or otherwise processed, keeping them all up-to-date can be a problem. Even more of a problem is passing them on to someone else (e.g., your instructor) and expecting them to know what to do to build your project from the source code.

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

A makefile may also include various macros/abbreviations designed to simplify the task of dealing with many instances of the same commands or files.

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

Press here to return to the Basic Unix Help Menu