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.
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.
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.
"file" (or file1, fileN, and newFile) all refer to files, and "dir" refers to a directory.
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).
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 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.
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).
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.
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 ...]
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
Find out your current working directory with the "print working directory" command:
> pwd /u/saponaraBut 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.
list the current directory:
> ls fileA fileB fileC fileDEF FileA FileB FileC FileXYZ
list a different directory:
> ls dir file1 file2 subDirectory1 subDirectory2
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
for example:
ls -l dir
options can be combined:
ls -la dir
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.
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
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 ..
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:
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
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
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.
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
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.
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 ? >>?]
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.
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
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).
Now that we can manipulate files, let's look inside at the data they contain.
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
more blahHit 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).
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
"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
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
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
There are many other text processing commands, generally included in the gnu textutils package. These include:
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
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:
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.
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:
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:
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.
You won't get very far without knowing how to edit files...
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. ]
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.
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.
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.
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.
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.
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.
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:
But if you want to put those heads each into a new file
with a ".head" extension on it, the following won't work:
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:
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:
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.
Any sequence of commands can be put into a file and executed
with the "source" command:
The shell startup files
(see user configuration) are examples
of shell scripts.
Alternatively, use the "chmod" command to make the script file
executable:
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:
or
or
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".
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.
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).
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:
or its C-shell equivalent:
Anything you find yourself typing repeatedly is a good candidate
for an alias. Here are some of my favorites (in Bourne shell
format):
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).
Aliases are one way to avoid typing long file paths such as:
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:
Similarly, if you're always changing to the /u/src/pilots/incl/PO
directory, you could enter:
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.
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.
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).
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 ]
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:
In Bourne shells, use "export":
Note that Bourne shells require an "=" symbol, and you cannot
surround it with spaces.
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.
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.
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:
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!
We're done. "bye" also works, "exit" won't work.
To create a tar file from a group of files or directories,
use the "c" option:
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:
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.
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").
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.
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.
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" 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.
compiles the file program.C and gives the resulting executable
the odd name "a.out", which is rarely what we want.
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:
does the same as above, but also looks in the directory
"/u/src/util" for header files. The compiler accepts multiple
include paths:
To define symbols (for conditional compilation using "#ifdef"),
use the "-D" option:
The order of these arguments doesn't matter.
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.
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!
sort file | uniq > uniquelySortedFile
ending input
> cat > newFile
your typing here
several lines is ok
whatever you want the file to contain
^D
> cat newFile
your typing here
several lines is ok
whatever you want the file to contain
Philosophical note
editing
vi & emacs & others
learning an editor
vim
shells
command history
name completion
midline listings
for/foreach
head f*
head f* > f*.head NOT!
foreach i (f*)
head $i > $i.head
end
for i in f*
do
head $i > $i.head
done
Shell scripts
> cat myScript
ls | grep myFile
> source myScript
[ myScript output appears here ]
chmod u+x myScript
#! /bin/sh
#! /bin/csh
#! /usr/local/bin/bash
user configuration
The user config files: .cshrc and .profile
aliases
alias lf='ls -F'
alias lf 'ls -F'
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'
links
/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.
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).
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.
Link gotchas
paths
set
environment
setenv DISPLAY mayer:0
export DISPLAY=mayer:0
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:
> 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.
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:
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.
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.
job control
.xsession
compiling and running programs
terms
cc/gcc/g++
g++ program.C
g++ program.C -o program
g++ -I /u/src/util program.C -o program
g++ -I /u/src/util -I /u/src/ninlib program.C -o program
g++ -DMY_SYMBOL -I /u/src/util program.C -o program
make and Makefile's
version control