tutorial preliminaries

These tutorials should be considered works in progress. If you find them confusing, please notify the author. As the tutorials evolve, they will (hopefully) become an asset to TDI, so your "bug reports" will contribute to smoother learning experiences for those who follow you.

John S.

Note from Ben B. to EEB users: these tutorials were written by John Saponara for people at his company, TDI. A little bit of the material is specific to his company's network, although most of it is generic. Sooner or later we may modify this document; for now, significantly site-specific parts are marked in italics.

Overarching philosophy

The idea is that folks are smart and documentation is out there already, so my goal is to tersely convey an overview of each skill set, mainly by example, and tell where to get more information. All this will be in html, thus easily viewed online or printed out.

Unix basics

Things everyone should know about Unix. Mostly an overview so that folks know these things exist and know where to find out more when they need to.

latest additions!

contents

[BB: possible additions-- It would be nice to have some kind of icon/indicator for material that may be *platform* or *variant*-specific (Solaris/SunOS/Linux/etc.) and one for material that may be *site*-specific (TDI/EEB). ]

Unix basics

There are many "flavors" of Unix, both free and commercial. They differ mostly in how they are administered--to the user, they are mostly the same. Here we present some basics that all "unices" share.

I call Unix a "deep" system, not because there's a lot one can learn about it (which there is), but because it consists of many pieces that one can put together in logical ways that the user comes to expect with experience. When you ask "Hey, I can do procedure X in situation Y, can I also do it in different situation Z?", the answer will either be yes, or the reason why you cannot do X on Z will show that a lot of thought went into the design of this OS.

terms

"file" (or file1, fileN, and newFile) all refer to files, and "dir" refers to a directory.

preliminaries

Unix is a multi-user system. Therefore, security is built in, and you must "log on" (or "log in") with a username and password. Your session starts in your "home directory". You are assigned to a "group" of users, such as group "tdi".

Each user has a default "shell" that interprets the commands you enter. The shell provides an environment with a number of important services that are discussed below. When you first log in, you see a "prompt" that usually ends with a greater-than symbol: ">". Just as in msdos, the prompt signifies the shell's readiness for your next command. In the Unix tutorials, the prompt is used to indicate the user's entry. Lines without a prompt show the shell's response.

All file and directory names are case-sensitive. Upper case is alphabetically before lower-case, and digits come before letters (in short, all characters are ordered by their ASCII code: '0'=48, 'A'=65, 'a'=97).

documentation

There is lots of online documentation in any Unix variant, but the machines that run linux (such as eagle) have by far the most complete online documentation. You can log onto eagle from any machine (such as by telnet'ing to eagle from the machine on your desk). So if your machine doesn't have one of the documentation sources listed below, try one of the linux boxes.

[BB: reorder these to put "man" above "info"?]

info

info is a character-based (that is, non-graphical), hyper- linked documentation system for packages. Just enter "info" and use the tab key to navigate among the topics. Enter "help" for a tutorial inside info.

man pages & the keyword option

Just about every Unix command has a "man page" (short for manual page, so any implied sexism is ancient). To see the man page for the ls command, enter:

man ls

What if you don't know the name of the command, but just know that you want some command that lists things? Try man with its keyword option:

man -k list

This displays a list of commands with a half-line description of each. This particular command line returns a very long list of commands, so you may want to filter it in some way (see below under grep).

online help

Both the sgi (running irix) and the rs/6000 (running aix) have online help systems accessible via menu and searchable through a gui. I haven't used these much, however.

news, faqs and rtfm.mit.edu

If you cannot find the information you need on any tdi machines (or tdi humans), you can use our internet connection to find the appropriate newsgroup and ask there. But before posting a question to a newsgroup, use ftp to go to the "faq" (frequently-asked question) repository at rtfm.mit.edu and get the faq (if any) for that news group. (See ftp below for an example.) [ BB: DejaNews, an archive of old Usenet news postings, is another good resource; after looking locally and trying to find a faq list and before posting a possibly common problem to the net, use DejaNews (http://www.dejanews.com/) to see if your question has already been discussed. If not, it may be time to post ...]

file & directory commands

quick-and-dirty file and directory creation

The following commands handle files and directories. If anything is unclear, try it! You'll learn these later, but use mkdir to make a directory, cd to jump into the directory, and touch to make files:

mkdir practice
cd practice
touch file1
touch file2
mkdir subDirectory

pwd

Find out your current working directory with the "print working directory" command:

> pwd
/u/saponara

But since /u/saponara is my home directory, many shells would instead print:

> pwd
~

The tilde character is used by many shells to abbreviate the user's home directory.

ls -- list

list the current directory:

> ls
fileA fileB fileC fileDEF
FileA FileB FileC FileXYZ

list a different directory:

> ls dir
file1 file2 subDirectory1 subDirectory2

options

Most Unix commands understand "options" that modify their behavior. Options are customarily put between the command's name and any required arguments: ls OPTIONS_HERE dir

useful options for the ls command

  • -f -- list files with a trailing character to indicate type
  • -a -- list all files (even those that begin with a dot, which are normally hidden).
  • -l -- long listing (includes size and creation date)

    for example:

    ls -l dir
    

    options can be combined:

    ls -la dir
    

    wildcards

    Specify files by substituting any of a list of characters for a single character in the filename:

    ls file[ABC]
    ls [fF]ile[ABC]
    

    Specify files by substituting any of a range of characters for a single character in the filename:

    ls file[A-Z]
    

    Substitute any character for a single character in the filename:

    ls file?
    

    Substitute any characters for any number of characters in the filename:

    ls file*
    

    Any combo is allowed:

    ls [fF]ile*
    ls *ile*
    

    Wildcards can be used on directory names too.

    cp -- copy

    You can copy a single file to a new name:

    cp file newFile
    

    Copy a file into a directory (the copy will have the same name as the original file):

    cp file dir
    

    Copy a file into a directory, giving the copy a new name:

    cp file dir/newName
    

    Copy several files into a directory:

    cp fileA fileB fileC dir
    

    useful options

  • -i -- interactive (user is prompted if a file/dir would be overwritten).

    special directories (. and ..)

    The current directory may be abbreviated with a dot:

    Copy a file from some other directory into your current directory:

    cp otherDir/file .
    

    [Unlike msdos, you must always specify the destination directory]

    The immmediate parent directory may be abbreviated with a double dot:

    ls ..
    

    mv -- move (and rename)

    To rename a file:

    mv file file2
    

    To move a file to another directory:

    mv file dir
    

    To do both at once:

    mv file dir/file2
    

    To rename a directory:

    mv dir dir2
    

    Directories can be moved into other directories, just as files can.

    useful options:

  • -i -- interactive (user is prompted if a file/dir would be overwritten).

    rm -- remove

    To remove a file or files:

    rm file
    rm file1 file2
    rm f*
    

    To remove a directory, you must use rmdir (see below) or the recursive option of rm (see below).

    useful options

  • -i -- interactive (user is prompted)

    mkdir/rmdir -- make/remove directories

    To make a directory:

    mkdir newDir
    

    To make several directories:

    mkdir newDir1 newDir2
    

    To remove a directory with rmdir, it must be empty:

    rmdir emptyDir
    

    To remove a non-empty directory, use

    cd -- change directory

    Go to a new directory:

    cd someOtherDir
    

    This can involve alot of typing:

    cd ../../dir/subDir
    

    If you find yourself typing many of these directory "paths", try using pushd/popd (see below). The wrist you save could be your own.

    recursive option (cp, rm)

    The recursive option is nearly always "-r" in Unix (sometimes "-R"). It extends the functionality of the command it modifies to all of a directory's contents, as many layers as you want. Try it out (or check the man pages if you're feeling cautious) for any given command.

    To copy an entire directory hierarchy, with all its files and subdirectories, and all their contents:

    cp -r dir newDir
    

    To remove an entire directory hierarchy (be careful with this command! there is no "undelete" command in Unix, so make sure you are really doing what you mean to):

    rm -r dir
    

    pushd/popd/dirs

    If you find yourself cd'ing among a small number of directories, you need a directory stack. Use pushd to cd to a new directory while telling the shell to remember where you're cd'ing from. Use pushd again to cd back from there while keeping both directories on your stack, or use popd to cd back and forget where you've been. Here's a sample session:

    > pwd
    ~
    > mkdir blah blah2
    > pushd blah
    ~/blah ~
    > pushd~ ~/blah 
    > pushd blah2
    ~/blah2 ~ ~/blah 
    > pushd +2
    ~/blah ~/blah2 ~ 
    > popd
    ~/blah2 ~ 
    > popd
    ~ 
    

    You can see that pushd can be used alone, to cd between your current directory and the most recent directory on the stack.

    Note that popd doesn't delete the directory you popped from, it only cd's you back and removes the popped dir from your directory stack.

    If you forget the contents of your current directory stack, you can get it with the "dirs" command:

    > dirs
    ~/blah ~/blah2 ~ 
    

    You can use cd while you have a directory stack--the top directory on the stack will always be your current directory.

    output redirection

    You can "redirect" the output of any command from the screen to a file with the ">" character; for example,

    ls > file
    

    just displays a prompt because the directory listing went into "file" rather than to the screen. If "file" already existed, its previous contents would be lost. [BB: noclobber ? >>?]

    permissions

    Recall that Unix is a multi-user system. When you log in, you authenticate yourself as a user, and you have access "permissions" on the contents of your home directory. The system of permissions can be used to facilitate collaborative work while maintaining the built-in security of Unix. Let's look at a "long listing" of a directory that contains a file and a subdirectory.

    > ls -l
    drwxrwx---    2 saponara tdi          512 May 22  1997 dir
    -rw-rw----    1 saponara tdi           26 May 22  1997 file
    

    For now, we're interested only in the first field. The first character of each line is "-" for files and "d" for directories. The remaining nine characters of that field are permissions. The permissions are divided into three types: read, write, and execute:

    [BB: emphasize or boldface read/write/execute?]

    If you have read    permission on a file,      then you can read    it.
    If you have write   permission on a file,      then you can edit    it.
    If you have execute permission on a file,      then you can execute it.
    If you have read    permission on a directory, then you can read    it.
    If you have write   permission on a directory, then you can edit    it.
    If you have execute permission on a directory, then you can cd into it.
    

    The directory permissions are a bit odd. The ls command first cd's into the directory, then reads its contents, so you cannot ls a directory without both read and execute permission. Write permission on a directory allows you to "edit" it--because a directory is really a list of files and subdirectories, "editing" a directory means changing that list, that is, either creating new files/directories or deleting files/directories.

    But why are there nine permission characters? Recall that every user is assigned to a "group" of users. User saponara happens to be in group "tdi". Every file and directory is owned by some user (typically the user that created it) and also by some group (typically the user's group). You can see from the long listing above that saponara is the user-owner of both items in the directory, and tdi is their group-owner. The first three permission characters are the permissions of the "user-owner" (here, saponara), the next three are for the "group-owner" (here, tdi), and the last three are for all other users:

       user  group  others
       rwx   rwx    rwx
       

    So:

    user saponara has read, write, and execute permissions on dir, but only read and write permissions on file (file is not executable).

    group tdi has identical permissions as user saponara. Thus all users in group tdi have access equal to that of saponara.

    "others" (that is, users other than saponara and those of group tdi) have no access to either item.

    chmod -- change "mode" or permissions

    Suppose user saponara doesn't want other members of group tdi to see or edit his file. Then he can change its permissions like this:

    chmod g-rw file
    

    Read "g-rw" as "group take-away read and write permissions". If saponara instead wants to offer everyone read (but not write) permission, he could enter:

    chmod o+r file
    

    umask -- the user's permission mask

    User saponara just noticed that his default file permission (that is, the permissions on a file created with "touch file") allows others in his group to read *and* write his files. He doesn't mind others reading his files, but he doesn't want them to edit his files. Instead, they should use their read permission to make their own copy of his files and edit that copy.

    Of course saponara could use chmod to restrict the permissions of already-existing files, but it would save much time if he could change the default permissions of new files (and directories). The reason "others" have no permissions on saponara's files is that saponara's "umask" is 007. The umask is three octal digits that specify a mask on the nine permissions:

       u   g   o
       0   0   7
       000 000 111
       rwx rwx ---
       

    so that anything saponara creates will have no permissions for others, but whatever permissions are appropriate for user and group. To "mask out" write permission for group, change the umask to 027:

       u   g   o
       0   2   7
       000 010 111
       rwx r-x ---
       

    So saponara just needs to enter:

    umask 027
    

    to restrict his default permissions for the desired effect. To avoid having to do this at the start of every login session, saponara can configure his account to do this automatically when he logs in by editing his shell's startup file (see below, under shells/startup files).

    text commands

    Now that we can manipulate files, let's look inside at the data they contain.

    cat -- concatenate files together

    To print a file to the screen, use the cat command:

    cat file
    

    As its description implies, it can be used to concatenate several files into one:

    cat file1 file2 file3 > bigFile
    

    cat -vet

    Some Unix commands (such as make , described below) and user-written programs are very picky about the format of files that they read as input. One perennial difficulty in checking file format is that you cannot easily distinguish spaces from tabs, and you cannot tell whether a line has trailing white space (white space means any combination of spaces and tabs). The cat command has options that mark tab as the control character that is really is (control-I, printed as "^I") and that marks the newline character at the end of each line (as "$") so that spaces and tabs look different and you can see exactly where a line ends. The options are -v, -e, and -t, and I always use them together, and I order them in a way that makes them easy to remember: just think of taking your cat to the "vet" and enter "cat -vet filename" to see the details of the file.

    more -- list a file a page at a time

    [BB] To see a long file a page at a time, enter:
    more blah
    
    Hit the space bar to go down a page, b to go back a page, q to quit without seeing the rest of the file, /foo to search for the string "foo" in the file (and ? for fancier options).

    grep -- search file contents for a pattern

    To see the lines of a file that contain the word "blah", enter:

    grep blah file
    

    If you specify a wildcard in the file position, it will search all files that match the wildcard.

    For example, if you enter "man -k list" (as suggested above) and get hundreds of lines of output, you could redirect the output to a file and search the file for the word "directory":

    > man -k list
    
    [too many lines here!]
    > man -k list > file
    > grep directory file
    ls (1)                  - list contents of directory
    

    regular expressions

    "grep" actually stands for "global regular expression print" and it allows you to search for patterns much more complex than exact matches. Patterns are specified in Unix via the "regular expression" syntax, and this same syntax works with a number of other Unix commands (such as sed and ex/vi), so it's worth getting an idea of what's possible. Here are the elements I find most useful, defined in a standard manner that is useless unless you already know regular expressions:

    ^        matches beginning of line
    $        matches end       of line
    .        matches any single character
    [abc]    matches any one of the characters contained.
    [^abc]   matches any one character *not* contained.
    *        matches zero or more of the preceeding pattern
    +        matches one  or more of the preceeding pattern
    ?        matches zero or one  of the preceeding pattern
    \.       use the backslash to "escape" the special meaning
             for all special characters: ., *, etc
    

    Some examples should help to clear up the confusing definitions:

    ^$       matches a blank line
    ^.$      matches a line with exactly one character
    ^[xyz]$  matches a line with any one of x, y, or z on it.
    ^[^ ]+   matches the first group of non-spaces on the line
    [0-9]    matches a digit
    

    and here's a less trivial pattern:

    [+-]?[0-9]*\.[0-9]* matches a floating point number

    diff -- differences between two files

    To find how two text files differ:

    diff file1 file2
    

    The output uses 'a' to indicate added hunks of lines, 'd' to show deleted hunks, and 'c' to show changed hunks. The direction is from file1 to file2, that is, what changes (and additions and deletions) are needed to change file1 into file2? Here is an example:

    > cat file1
    a 
    b
    c
    1
    2
    3
    x
    y
    z
    > cat file2
    a
    b1
    c
    x
    y
    z
    A
    B
    C
    > diff file1 file2
    2c2
    < b
    ---
    > b1
    4,6d3
    < 1
    < 2
    < 3
    9a7,9
    > A
    > B
    > C
    

    useful options

  • -w ignore whitespace differences

    head/tail -- display the beginning/end of a file

    To show the first ten lines of a file:

    head file
    

    To show its last ten lines:

    tail file
    

    Both head and tail accept a numeric option that controls how many lines are displayed (that is, the option allows you to override the default of ten lines):

    head -20 file
    

    Using head is a nice way to view a group of files:

    > head file?
    ==> file1 <==
    a
    b
    c
    1
    2
    3
    x
    y
    z
    

    ==> file2 <== a b1 c x y z A B C

    other Unix text processing commands

    There are many other text processing commands, generally included in the gnu textutils package. These include:

  • sort -- sort lines of a file
  • uniq -- eliminate consecutive duplicate lines (used after sort)
  • tr -- translate characters (for example, convert upper to lower case)
  • comm -- show lines that two files have in common (or that they don't)

    These utilities (like all the text utilities discussed here) don't change the file--their output is printed to the screen. Thus if you want to save that output, you should redirect it to a file:

    sort file > sortedFile
    uniq sortedFile > uniquelySortedFile
    

  • pipes (|)

    Creating all these intermediate files can be inconvenient and even confusing, so Unix allows all these utilities to communicate directly via the "pipe" mechanism, represented by the "|" character:

    sort file | uniq > uniquelySortedFile
    

    You see that the intermediate file, "sortedFile", is no longer created. Even the OS does not create this file--the pipe arranges direct communication between utilities, so that the output of sort becomes the input of uniq. User's programs that write to the screen (to "standard output", also called "stdout") and read from the keyboard (from "standard input" or "stdin") can also be strung together in pipes.

    ending input

    How does a utility that's waiting for input from stdin know that the input has ended? It quits when it receives the Unix end-of-file character, Control-D. So here's another quick-and-dirty file creation method:

    > cat > newFile
    your typing here
    several lines is ok
    whatever you want the file to contain
    ^D
    

    Note that we told cat where to put its output, but didn't mention where it should get its input. Because it's one of the Unix text utilities, its input defaults to stdin, so anything the user types will go into the file. We can use cat to display the file to the screen:

    > cat newFile
    your typing here
    several lines is ok
    whatever you want the file to contain
    

    Philosophical note

    Unlike consumer OS's, where the trend has been to build ever-bigger programs with more functionality (such as word processors with built-in spreadsheet capabilities, and spreadsheets that overlap with word processors), Unix is built on small utilities that do a small job flexibly and that can be strung together in pipes to accomplish complex tasks. Check the man pages for the options that suit you (for example, sort can sort in reverse, and uniq can show *only* duplicate lines, depending on the options you use). Shell scripts can be constructed that automate any task that you can do by hand, so that you need never do repetitious tasks again.

    editing

    You won't get very far without knowing how to edit files...

    vi & emacs & others

    The original Unix editors were line-based editors, meaning they only showed the user one line at a time. Later, screen-based editors appeared and users could see an entire screen-ful of their file. The only screen-based editor that comes with all flavors of Unix is "vi" (which stands for "visual", because it's the screen-based version of "ex", one of the line editors). Vi is called a "bimodal" editor because the meaning of each key depends on the current mode, of which there are two: in insert mode, keys have the usual meaning (I'm typing in insert mode), but in command mode, each key becomes a command (for moving around the screen, deleting text, and of course, for entering insert mode. Beginners dislike vi because it's easy to forget that you're in command mode and just start typing, which can have unpredictable results :)

    More popular today is the emacs editor (from the FSF folks), which is unimodal (like a word processor). It forces you to hit more keys for any given job (especially the control key), but folks who don't edit very much find it easier to learn. Unfortunately, emacs has taken a rather un-Unix-like path and become a mail-reader, news-reader, shell, and even provides a lisp interpreter and a pseudo-psychotherapist mode. It has become an environment that the user need never leave, but in doing so it has grown to consume considerable system resources.

    Other editors abound. Popular among sgi users at tdi is "jot". But nearly all such editors are platform-specific, so tdi folks should choose either vi or emacs and learn it well. They are both available for all pc OS's as well as all Unix flavors. Other platform-independent editors are joe, jove, and pico.

    The decision of which to use is mostly up to individual taste, but I strongly urge all implementers to choose vi. Vi is guaranteed to be available on all Unix platforms, and you may find yourself sitting at a new, unconfigured machine at a client site someday, with only the built-in editor (vi) available.

    [BB: I recommend that beginners use pico (it has the smallest start-up costs), then switch to vi or emacs when they're comfortable or when they outgrow pico and want to do complex editing tasks. In my view there is little reason to use vi instead of vim if vim is available. ]

    learning an editor

    Emacs has a built-in tutorial (after starting emacs, type "Control-H t"). In fact, it has built-in everything, so the tutorial is not surprising. There is an O'Reilly book on emacs, but tdi doesn't have it.

    The best way to learn vi is with vilearn. [ to be installed--if the following doesn't work, tell John S. ] Just enter "vilearn" and choose among the half-dozen or so 15-minute sessions. It just puts you in vi, loads one of its tutorial files, and you read the file and do the edits right on the file. It's a nice way to get started with vi.

    There's also an O'Reilly book on vi, which I think is floating around tdi somewhere.

    vim

    Vi is rather spartan and is not free software, so several look-alikes have been written: vim, elvis, stevie are some I have tried. My favorite is vim ("vi improved"), and all of our systems have some version of vim on them. Vim does have a help mode (enter ":help"), but it's more of a reference than a tutorial.

    shells

    Each user is put into their default shell upon logging in. There are two kinds of shells, Bourne shells and C-shells. The Bourne shell was the original Unix shell. The C-shell came later and added some nice features. Each has a number of descendants.

    At tdi, the most popular shells are a C-shell called tcsh and a Bourne shell called bash (for Bourne-again shell, from the FSF). As far as I know, they offer almost the same set of features. Most important is that you know of the features and use them to save you time.

    command history

    All up-to-date shells save a "history" of your commands. Try up-arrow or Control-P (for Previous) to access these commands. Move back to more recent commands with the down-arrow or Control-N (for Next). If this doesn't work, you'll need to edit your shell's startup file to set the size of your history buffer (see user configuration section).

    Once you bring up a previously entered command, you can use the arrow keys and backspace key to edit it if needed.

    name completion

    While entering a long filename or directory pathname, any decent shell will allow you to request automatic completion of the name by hitting the tab key. If you've not yet typed enough characters to specify a file uniquely, the shell will complete up to the first divergent character, and will beep to prompt you to decide which possibility you want.

    midline listings

    If you're beeped at during name completion, you may want to see a list of all possible matches to what you've typed so far. Under tcsh, hit Control-D to get this list; under bash, hit tab twice (in rapid succession). After the listing, the shell reconstructs your partially-typed command line for you to continue.

    for/foreach

    Wildcards help avoid some repetitious typing. "For loops" help avoid even more. For example, if you want to display the heads of all files starting with f, you can enter:

    head f*
    

    But if you want to put those heads each into a new file with a ".head" extension on it, the following won't work:

    head f* > f*.head		NOT!
    

    This won't work because the shell expands wildcards before doing anything. So if there are no "f*.head" files yet, there will be an error. If some files have names that match "f*.head", then they will all appear in place of that wildcard on the command line, and the head output will all go into the first .head file, and the rest of the list will cause an error (the shell won't know what you want done with them).

    Here's how you do it in a C-shell:

    foreach i (f*)
    head $i > $i.head
    end
    

    After the first line, the shell will give you a "foreach?" prompt for each line until after you enter the "end" statement, to confirm that you are still defining a foreach loop.

    Here's how you do it in a Bourne shell:

    for i in f*
    do
    head $i > $i.head
    done
    

    Note that "i" is an arbitrary variable name (a "dummy" loop variable) that need merely be consistent. The variable is defined in the for/foreach statement, then its value is accessed in subsequent statements by prepending a "$" to the variable name.

    Shell scripts

    Any sequence of commands can be put into a file and executed with the "source" command:

    > cat myScript
    ls | grep myFile
    > source myScript
    [ myScript output appears here ]
    

    The shell startup files (see user configuration) are examples of shell scripts.

    Alternatively, use the "chmod" command to make the script file executable:

    chmod u+x myScript
    

    and omit the "source" command, using the file directly as an executable.

    The comment character for shell scripts is "#", which comments out the rest of the line.

    Optionally, you can specify which shell should execute your script by naming the shell on the script's first line, following "#!" as the first two characters of the line:

    #! /bin/sh
    

    or

    #! /bin/csh
    

    or

    #! /usr/local/bin/bash
    

    The mnemonic for remembering that pair of characters is: "she-bang" for sharp-bang. Note that syntactically, it's a shell script comment.

    For more on shell scripting, see the Appendix on "Bourne Shell Programming" in Aeleen Frisch's best-selling book, "Essential System Administration".

    user configuration

    Once you have an editor in hand, you can begin to configure your environment. When you log in, your default shell runs a list of commands that do lots things for you. You, too, can edit that file and modify your default environment.

    Many of the tools described in this section are designed to save you keystrokes. For folks who spend lots of time computing, these tools can reduce the risk of carpal tunnel syndrome--this is important stuff, not merely convenient.

    The user config files: .cshrc and .profile

    Users of C-shells (such as csh and tcsh) have a .cshrc file in their home directory. The "rc" at the end of that filename means "run commands", and indeed, the file contains commands that the shell runs on startup. Bourne shell users have a (less appropriately named) .profile file in their home directory. Other shells may use other files (bash uses .bashrc), but usually only after running the commands in the generic startup file (.cshrc for C-shells, .profile for Bourne shells).

    aliases

    All shells let you define aliases to save typing. For example, if you find yourself using "ls -F" rather than simply "ls" because it gives you so much more information, this Bourne shell alias:

    alias lf='ls -F'
    

    or its C-shell equivalent:

    alias lf 'ls -F'
    

    Anything you find yourself typing repeatedly is a good candidate for an alias. Here are some of my favorites (in Bourne shell format):

    alias lf='ls -F'
    alias ll='ls -l'
    alias show='cat -vet'
    alias +x='chmod u+x'
    alias -x='chmod -x'
    alias pu='pushd'
    alias po='popd'
    alias pd='dirs'
    alias psg='ps aux | grep $1'
    alias le='vi ~/.bashrc'
    alias lx='source ~/.bashrc'
    

    Note the psg alias, third-from-last. It includes a pipe and takes an argument. The "$1" is replaced by the first argument the user types after the alias name. So if the user enters "psg blah", the shell will run the command "ps aux | grep blah" (which looks for blah in the process listing of the machine you're logged into).

    Note also the last two aliases, le and lx--they edit and execute (respectively) the startup file for the shell I use (bash). So this way it's easy for me to add a new alias. Just editing the startup file only changes future login sessions--to add the alias to your current session, you must then execute the modified startup file. That's the purpose of "lx". Choose names that suit you, mine are arbitrary.

    If you want an alias for the current session only (and don't want it in your startup file), just enter it at the command line. Be aware, though, that the startup file is executed once for every window you have open, so new aliases must be executed in every window where you need them (this goes for using "lx" too).

    links

    Aliases are one way to avoid typing long file paths such as:

    	/u/bin/aix-4.1.5.0/g++/my_executable
    	
    or
    	cd /u/src/pilots/incl/PO
    	
    You could easily define aliases to execute some of the longest lines that you commonly type. But one disadvantage of aliases is that they clutter up your list of shell variables, and they tend to stay there long after they've become less useful. If you don't use an alias, you don't see it, and I tend to never get around to cleaning them up. Long lists of shell variables cause a performance penalty: because all the alias definitions must be read in for each new shell you create, and a shell is created for each window you open, these long shell variable lists actually slow the opening of new windows. But the main penalty is greater difficulty in managing your shell variables, finding whether you've already defined an alias for a given purpose, etc.

    Because most of these lengthy commands involve disk access (executing files or changing directories), the "alias" feature of other OSs, in which a file or directory can be accessed from more than one place in the directory hierarchy, would be a good way to address this problem. Unix, of course, had these "file and directory aliases" long before most of those other OSs were born, and they're called links.

    Links provide additional points of access to a file or directory. To create a link, use the "ln" command. For now, stick to the "-s" option (explained below). Thus, to replace the "/u/bin/aix-4.1.5.0/g++/my_executable" line, you might enter:

    	cd ~
    	ln -s /u/bin/aix-4.1.5.0/g++/my_executable my_exec
    	
    and a "my_exec" file will appear in your home directory. The name "my_exec" is arbitrary--call the link whatever you want. To execute the far-away my_executable file, you can now just enter "my_exec". If you do an "ls -F" you'll see that the link's name is followed by a "@" denoting that it is a link (the real file is "at" another place on the disk).

    Similarly, if you're always changing to the /u/src/pilots/incl/PO directory, you could enter:

    	ln -s /u/src/pilots/incl/PO po
    	
    and henceforth you can just "cd po" to reach that far-away directory. To edit a file in that directory, just "vi po/filename"--the link acts just like the directory.

    The "-s" option of ln makes the link "symbolic". That means it stores the name of the file or directory to which it points (let's call the pointed-to item the link's "referent"). Without the "-s" option, the ln command creates a "hard" link. Hard links store a location on the hard drive. Although hard links are dereferenced a bit more quickly than symbolic (or "soft") links, all hard links must reside on the same physical hard drive as the their referents, whereas soft links can point across hard drives or even across the network to a file mounted from another machine. Because of their greater flexibility, use soft links exclusively.

    Link gotchas

    If a symbolic link's referent is deleted, the link still points to that name, but any attempt to use the link (except to remove the link itself) will return an error message.

    Commands that process files and directories vary in how they treat soft links that point to directories--such a soft link could be treated either as a file (that happens to be a link) or as the directory it points to. For example, the find command recursively descends down thru a directory hierarchy to seek files that satisfy a given set of criteria. Should it descend into the directories pointed to by soft links or not? Like most such commands, find provides an option for the user to specify whether it should follow soft links to directories into their referents or just treat them as files.

    paths

    When you enter a command, the shell is responsible for interpreting it. Your startup file defines an "execution path", which is a list of directories the shell will check for the filename you enter. The "command not found" error message is issued only after all the directories on your path have been searched. Make sure your path includes "/usr/local/bin" because it is where we put most of the gnu utilities (except on linux, which comes with all the gnu stuff in /usr/bin).

    There are other paths. For example, your manpath is the list of directories in which man pages are sought. But the execution path is the most commonly used.

    To find your current path, use the "set" command (see below).

    set

    Your shell has a slew of special values defined, the most important being your execution path. To see all that stuff, enter "set". You can use "set" to change any of those values.

    [ demo of changing execution path to appear here ]

    environment

    Another set of values, called the user's "environment", is defined independent of the shell. The environment variables are always all-uppercase. The most commonly used environment variable is DISPLAY, which tells X which host to display windows on (in X, you can run a program on a remote host, yet ask for the program to display its windows on the host at which you sit). To see your environment variables and their values, use the "env" (or "printenv") command. In C-shells, use "setenv" to set an environment variable, and "unsetenv" to eliminate it:

    setenv DISPLAY mayer:0
    

    In Bourne shells, use "export":

    export DISPLAY=mayer:0
    

    Note that Bourne shells require an "=" symbol, and you cannot surround it with spaces.

    transferring information

    All of us need to download archives of files from the net occasionally, and TDI implementers upload archives of source code or executables for our clients to download and use. Here's how.

    ftp

    The main repository of internet "FAQs" (frequently asked question lists) is at MIT on the host rtfm.mit.edu, and that hostname nicely reflects the attitude of many netsters to folks who post questions to news groups before reading the FAQ (rtfm stands for "read the f___ing manual"). We wouldn't want the TDI name in the signature of anyone who failed to read the FAQ before posting a question answered in that document, so here's a sample session to demonstrate how to use ftp (file transfer protocol) to get a file from rtfm. I'm using ">" to represent the command prompt, and I'll indent the remote host's responses for ease of reading.

    > ftp rtfm.mit.edu
    	Connected to BLOOM-PICAYUNE.MIT.EDU.
    	220 rtfm ftpd (wu-2.4(60) with built-in ls); bugs to ftp-bugs@rtfm.mit.edu
    	331 Guest login ok, send your complete e-mail address as password.
    	230 Guest login ok, access restrictions apply.
    	binary
    	200 Type set to I.
    	cd pub/usenet
    	250-| COPYRIGHT NOTICE
    	250-| ~~~~~~~~~~~~~~~~
    	250-| Nearly all of the files contained in this directory are copyrighted
    	250-| by their respective maintainers.  (Even files without explicit
    	250-| copyright notices are copyrighted under the international Berne
    	250-| Convention, in effect in most countries.)  Some of the files,
    	250-| although certainly not all, prohibit redistribution for any
    	250-| commercial purposes without prior approval; other kinds of
    	250-| restrictions may also be imposed by the maintainers.
    	250-| 
    	250-| Approval for use when there are restrictions imposed must be
    	250-| obtained from the maintainers of each file, *NOT* from the
    	250-| maintainers of this archive.  If you have any doubts about whether
    	250-| you may redistribute a particular file for some particular purpose,
    	250-| contact its author.
    	250-| 
    	250-| Making a copy for your own personal reading is implicitly allowed.
    	250-
    	250 CWD command successful.
    	Remote system type is UNIX.
    	Using binary mode to transfer files.
    ftp> cd /pub/usenet-by-group/comp.lang.c++
    	250 CWD command successful.
    ftp> ls
    	200 PORT command successful.
    	150 Opening ASCII mode data connection for /bin/ls.
    	total 1396
    	drwxrwxr-x   3 root     3             512 Sep 15  1996 C++-faq
    	-rw-rw-r--   2 99       3           42069 Nov 11  1996 C++_FAQ_(#1_of_7)
    	-rw-rw-r--   2 99       3           59878 Nov 11  1996 C++_FAQ_(#2_of_7)
    	-rw-rw-r--   2 99       3           57306 Nov 17  1996 C++_FAQ_(#3_of_7)
    	-rw-rw-r--   2 99       3           61689 Nov 12  1996 C++_FAQ_(#4_of_7)
    	-rw-rw-r--   2 99       3           55715 Nov  7  1996 C++_FAQ_(#5_of_7)
    	-rw-rw-r--   2 99       3           59877 Nov  7  1996 C++_FAQ_(#6_of_7)
    	-rw-rw-r--   2 99       3           10572 Nov  7  1996 C++_FAQ_(#7_of_7)
    	-rw-rw-r--   6 99       3           45186 Jan 18 01:07 C++_FAQ_(part_1_of_7)
    	-rw-rw-r--   6 99       3           50911 Jan 18 01:07 C++_FAQ_(part_2_of_7)
    	-rw-rw-r--   6 99       3           56738 Jan 18 01:07 C++_FAQ_(part_3_of_7)
    	-rw-rw-r--   6 99       3           55803 Jan 30 00:57 C++_FAQ_(part_4_of_7)
    	-rw-rw-r--   6 99       3           57052 Jan 19 00:21 C++_FAQ_(part_5_of_7)
    	-rw-rw-r--   6 99       3           50428 Jan 19 00:21 C++_FAQ_(part_6_of_7)
    	-rw-rw-r--   6 99       3           55623 Jan 18 01:07 C++_FAQ_(part_7_of_7)
    	-rw-rw-r--   4 99       3           67082 Feb  4 01:50 FAQ_for_g++_and_libg++,_plain_text_version_[Revised_01_Feb_1997]
    	-rw-rw-r--   4 99       3           66884 Jan 17 01:08 FAQ_for_g++_and_libg++,_plain_text_version_[Revised_16_Dec_1996]
    	-rw-rw-r--   4 99       3           68427 Apr 16 00:45 FAQ_for_g++_and_libg++,_plain_text_version__[Revised_01_Apr_1997]
    	-rw-rw-r--   8 99       3           68558 Jul  2 00:43 FAQ_for_g++_and_libg++,_plain_text_version__[Revised_01_May_1997]
    	-rw-rw-r--   4 99       3           68412 Mar 15 12:12 FAQ_for_g++_and_libg++,_plain_text_version__[Revised_13_Mar_1997]
    	-rw-rw-r--   4 99       3           81816 Feb  4 01:05 FAQ_for_g++_and_libg++,_texinfo_version_[Revised_01_Feb_1997]
    	-rw-rw-r--   4 99       3           81347 Jan 17 01:04 FAQ_for_g++_and_libg++,_texinfo_version_[Revised_16_Dec_1996]
    	-rw-rw-r--   4 99       3           83292 Apr  2 00:59 FAQ_for_g++_and_libg++,_texinfo_version__[Revised_01_Apr_1997]
    	-rw-rw-r--   8 99       3           83350 Jul 10 00:46 FAQ_for_g++_and_libg++,_texinfo_version__[Revised_01_May_1997]
    	-rw-rw-r--   8 99       3           26702 Jun  4 02:37 hush_(hyper_utility_shell)_FAQ
    	-rw-rw-r--   1 99       3             594 Jul 15 04:19 index
    	226 Transfer complete.
    ftp> prompt
    	Interactive mode off.
    ftp> mget C++_FAQ_*part*
    	local: C++_FAQ_(part_1_of_7) remote: C++_FAQ_(part_1_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_1_of_7) (45186 bytes).
    	226 Transfer complete.
    	45186 bytes received in 18.2 secs (2.4 Kbytes/sec)
    	local: C++_FAQ_(part_2_of_7) remote: C++_FAQ_(part_2_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_2_of_7) (50911 bytes).
    	226 Transfer complete.
    	50911 bytes received in 15.4 secs (3.2 Kbytes/sec)
    	local: C++_FAQ_(part_3_of_7) remote: C++_FAQ_(part_3_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_3_of_7) (56738 bytes).
    	226 Transfer complete.
    	56738 bytes received in 25.8 secs (2.1 Kbytes/sec)
    	local: C++_FAQ_(part_4_of_7) remote: C++_FAQ_(part_4_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_4_of_7) (55803 bytes).
    	226 Transfer complete.
    	55803 bytes received in 25 secs (2.2 Kbytes/sec)
    	local: C++_FAQ_(part_5_of_7) remote: C++_FAQ_(part_5_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_5_of_7) (57052 bytes).
    	226 Transfer complete.
    	57052 bytes received in 27 secs (2.1 Kbytes/sec)
    	local: C++_FAQ_(part_6_of_7) remote: C++_FAQ_(part_6_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_6_of_7) (50428 bytes).
    	226 Transfer complete.
    	50428 bytes received in 19.8 secs (2.5 Kbytes/sec)
    	local: C++_FAQ_(part_7_of_7) remote: C++_FAQ_(part_7_of_7)
    	200 PORT command successful.
    	150 Opening BINARY mode data connection for C++_FAQ_(part_7_of_7) (55623 bytes).
    	226 Transfer complete.
    	55623 bytes received in 30.7 secs (1.8 Kbytes/sec)
    ftp> quit
    	221 Goodbye.
    > ls C++*
    	C++_FAQ_(part_1_of_7)  C++_FAQ_(part_4_of_7)  C++_FAQ_(part_7_of_7)
    	C++_FAQ_(part_2_of_7)  C++_FAQ_(part_5_of_7)
    	C++_FAQ_(part_3_of_7)  C++_FAQ_(part_6_of_7)
    >
    
    The commands issued at the ftp prompt are:

    cd /pub/usenet-by-group/comp.lang.c++

    The usenet-by-group directory has a flat (and thus huge) list of all the news groups that have FAQs, so you need to know the exact name of the group whose FAQ you want. If you're unsure of the name, go to /pub/usenet-by-hierarchy and list (with the ls command) each level separately. This way you would work your way down to /pub/usenet-by-hierarchy/comp/lang/c++ with manageable directory lists along the way.

    ls

    The "ls" command works in ftp as in any shell. If you accidentally ask for a huge listing, ^C will eventually interrupt the listing, but it may take awhile, so be careful.

    prompt

    We see that the faq is divided into seven files, and we want them all. So we'll use the mget (multiple get) command rather than issuing a separate get command for each file:

    > get file1
    ...
    > get file2
    ...
    
    But even with mget, the ftp server on the remote host will ask us whether we want each file that matches the wildcard pattern we specify, and will wait for us to say yes to each one. I like to be able to walk away (or work in a different desktop) while I'm doing a long ftp, so I use the "prompt" command to toggle prompting off.

    mget C++_FAQ_*part*

    Finally, I get my files. Noticing that there are two groups of files, one apparently newer than the other, I choose the newer group by specifying the string "part" in the pattern. I also used wildcards to avoid dealing with the parentheses that are part of the name, since I always forget whether I must escape them with backslashes, and if so how many backslashes!

    quit

    We're done. "bye" also works, "exit" won't work.

    Unix archives

    Despite its name, the rtfm host is set up in a very friendly way: its files are not compressed. Once you've become accustomed to working with Unix archives, you'll wish rtfm archived those groups of seven files. A Unix archive is much easier to handle than the distribution of files from which it was created (because it's a single file), and it can be ftp'd much faster because it is compressed. A Unix archive is created in two steps: the files (even an entire directory hierarchy) is collected into one (not compressed) file with the "tar" command, and then the resulting single file is compressed, using either the "compress" command or its gnu equivalent, gzip. Because each stage adds a file extension, Unix archives can be recognized by their endings, most commonly: .tar.Z or .tar.gz, or combined (to accommodate the alleged OS, msdos) as .trz or .tgz

    tar

    The "tar" command can collect any number of files and directories, even an entire hard drive, into a single file. Its earliest use was to archive data to tape backup units, as its name reflects: tar = Tape ARchiver. Oddly, tar options are not prepended by a minus sign. I mainly use just three combinations of tar options:

    To create a tar file from a group of files or directories, use the "c" option:

    tar cvf newfile.tar [list of files and/or directories]
    
    The "f" option means that a filename is next on the command line. The "v" option causes tar to list each file as it is put into the archive.

    Most likely you'll now want to compress the archive (see below) and ftp it somewhere (or just store it on a floppy). But to make sure the tar command did as you told it, you might want to list its contents.

    To list the contents of a tar file, use the "t" (for "table of contents") option:

    tar tf newfile.tar
    
    To extract the contents of a tar file, use the "x" option:
    tar xvf newfile.tar
    
    Extracting a tar file is most commonly done after decompressing a Unix archive file, described below.

    compress/gzip

    A tar file is not a Unix archive because it has not yet been compressed. To compress a tar file (or any file), use either the compress command or its gnu version, gzip:
    compress file.tar
    gzip anyFile
    
    Both commands will replace the original file with the compressed file, and indicate that compression has occurred by appending a file extension: ".Z" for compress, ".gz" for gzip.

    To decompress a file, use "compress -d" or "gzip -d" (or simply "gunzip"). Gzip can decompress .gz and .Z files, but compress only handles .Z files, so I always just use gzip/gunzip.

    job control

    If you're in an editor, and need to jump out to check mail (or do anything you can't do in the editor), and don't feel like opening another window, suspend your editor (or other application) with the Control-Z key. You'll get a shell prompt, and you can do anything you can normally do from a shell. If you enter "jobs", you'll see the suspended editor (and any other apps you've suspended) in a numbered list. Enter "%1" to restart the first app in the list ("%2", etc). To restart the most recently suspended job, you can also enter "fg" (for "foreground").

    .xsession

    This is a startup file that X looks at to set up your initial screen. If you want a clock of a certain size and position, and a calculator, etc, this is where you need to go.

    compiling and running programs

    We compile and run executables on a daily basis--here's how. This section assumes you've written a program in C or C++. See the tutorials on C++ to get started on that language.

    terms

    A "header file" expresses the interface of a program module to other modules in the program. It's the programmer's way of saying "this module may be arbitrarily complicated, but here's all you other modules need to know about it". Header file names end in ".h"

    A "source file" contains the code that actually implements all that complexity. C source file names end in ".c", and C++ source file names end in ".cc" or ".C" or ".cpp"

    cc/gcc/g++

    "cc" stands for "C compiler", and it used to come with every version of Unix. Recently, an increasing number of vendors are selling their compilers separately. These vendors generally sell respectable C compilers and poor C++ compilers. Although we have used vendor C compilers in the past, we are now moving away from C and toward C++. All of our new code is in C++. Rather than use poor vendor-supplied C++ compilers, we use the g++, the gnu C++ compiler from the Free Software Foundation. Their C compiler is called gcc.

    All of these compilers accept the same basic options, so we'll use g++ in the following examples.

    g++ program.C
    

    compiles the file program.C and gives the resulting executable the odd name "a.out", which is rarely what we want.

    g++ program.C -o program
    

    Does the same as above, but names the resulting executable "program". Unix doesn't use ".exe" as a special extension for executables.

    If you include header files that are not in the current directory, use the "-I" option:

    g++ -I /u/src/util program.C -o program
    

    does the same as above, but also looks in the directory "/u/src/util" for header files. The compiler accepts multiple include paths:

    g++ -I /u/src/util -I /u/src/ninlib program.C -o program
    

    To define symbols (for conditional compilation using "#ifdef"), use the "-D" option:

    g++ -DMY_SYMBOL -I /u/src/util program.C -o program
    

    The order of these arguments doesn't matter.

    make and Makefile's

    Early in your career here, you'll find yourself compiling a single program from many source and header files in many directories. To automate this process, we use the "make" utility. Make is smart enough to check the timestamp on each file that goes into a program to see if it needs to be recompiled; if so, it invokes the compiler. This way if you've changed only 2 of the 35 files of a program, make will tell the compiler to recompile only those two that you changed. This is called "project management".

    But make isn't smart enough to read your mind--instead, it can read a Makefile that is written to define which files depend on which others. For example, the executable depends on 35 source files, and each source file depends on the header files it includes. So if you change a header file, any source files that include it should be recompiled. If your Makefile accurately expresses all the dependencies among the files in your program, then merely typing "make" will do whatever is needed to produce an executable.

    In practice, the Makefile for your project will usually be written by someone else. Have a look at the Makefile in your first project--you'll find that you can understand most of it, and after asking what a couple of the funny symbols mean, nearly all of it. But writing your own Makefiles is not for the beginner.

    version control

    RCS basics

    The Revision Control System, or RCS, is free (covered by the Gnu Public License) version control software for Unix and many other platforms. It consists of several utilities for managing a "database" of file revisions. This function is critical in an organization that sells software--in order to reproduce a client's problem, we must be able to easily call up the exact version of the software. TDI's (presumably newer) current version is irrelevant to the client's immediate problem, and the fix we send the client is not necessarily the best fix for the current version.

    Another potential problem is when folks work simultaneously on the same source file. To avoid such snarls, some locking system is needed.

    RCS provides excellent solutions to these problems at the file and single-directory level. Higher levels, such as a group of source directories, must be addressed with a more sophisticated system. See forthcoming information on hpm, our hierarchical patch manager.

    Here is an outline of typical use of RCS--I'll leave the comprehensive info to the man pages for the commands (listed below). There is also a nice introduction to RCS in the "rcsintro" man page.

    -- ci --

    Let's say you have a file that has some meaning for you--for example, you've finally gotten a program (consisting of a single file) to run, and now you want to start adding features. The thought of editing something that works should make you feel a bit nervous and is an excellent opportunity to start revision control for your program. RCS creates a version file for each file it manages, so to avoid cluttering up your directory, create an RCS directory: mkdir RCS and then check in your file: ci -l myfile.c RCS asks for a comment that it will record for that file--for the first check-in, just write what the file does, and anything else you think is important. For future check-ins, you'll just summarize the changes you made since the previous check-in.

    That "-l" option on the ci command tells check-in not to remove your file (which it will by default) but instead to keep a locked copy (the "working file") out for you to continue editing. This "lock" prevents others from editing the file. Of course, if you own the file and it isn't group-writeable, no user (other than root) can edit it anyway, but locking is a good habit to get into for when we're editing files owned by generic users such as "pilots".

    By default, RCS numbers versions 1.1, 1.2, ... 1.9, 1.10, 1.11, etc. But the ci command accepts a revision option, so to make the next version 2.1 (rather than, say, 1.12), use: ci -l -r2 myfile.c or ci -l -r2.1 myfile.c

    For multiple .c and .h files, just use wildcards: ci -l *.[hc] After the first file, ci asks if you want to use the same log message for each subsequent file, so you don't have to type endlessly.

    -- co --

    If you forget the "-l" option, your working file is removed by ci. Not to worry, just enter: co -l myfile.c to check the file out again (and leave it locked so no one else can check it out). If you omit the lock option from the co command, the checked out copy will not be writeable, only readable. Don't use chmod to change this--learning to work within the RCS confines will make it a tool rather than an obstacle.

    -- rcsdiff --

    If you want to see the changes you've made since the last check-in, enter: rcsdiff myfile.c As with ci, rcsdiff accepts revision options: rcsdiff -r1.2 myfile.c gives diffs between the working file and revision 1.2, and rcsdiff -r1.2 -r1.3 myfile.c gives diffs between revision 1.2 and revision 1.3

    -- ident --

    To mark your working files with the current version number, put $Id$ somewhere in the file. In C files, it is convenient to put this marker in a comment at the top of the file. If you want it in your object and executable files as well, use: static char rcsid[] = "$Id$"; Our C++ compiler to smart enough to see that this array is never used, and doesn't let it pass through. Trevor's fix for this will appear here shortly.

    Once you put a marker in your file, you can use the ident command to extract version information from it.

    -- rlog --

    To get the complete list of log messages, use the rlog command (it also takes revision flags).

    -- rcsfreeze --

    And finally, you can freeze a group of files as a single revision with rcsfreeze. Rcsfreeze is a dumb script, accepting only an optional symbolic name for the current version of all the currently checked-in files in the current directory.

    -- multiple branches --

    Eventually, we'll want multiple branches of the revision tree for certain files. This is achieved by adding a third number to the revision in the ci command: ci -l -r1.12.1 myfile.c creates another branch numbered 1.12.1.1, 1.12.1.2, etc. Branches allow parallel threads of development by different developers. Branches can be merged with the rcsmerge command.

    Complete list of RCS commands installed at TDI:

    ci, co, rcs, ident, rlog, rcsclean, rcsfreeze, rcsmerge, rcsdiff and don't forget the "rcsintro" man page!