The Shell
Overview:    Shells are UNIX programs that allow a user to interact with UNIX
             in order to manipulate files, deal with programs, communicate
             with other users, and in general use UNIX effectively.  They are
             large complex systems that take a while to learn.  In earlier
             lessons, many details of shells have been introduced.  In this
             tutorial, several important topics are dealt with coherently.

Section                             Topic
-------                             -----

   How shells work
   History (how to redo earlier commands)
   The command path
   Running programs in the background
   Job Control
   Wildcard characters
   Command pipelines
   Command substitution
   Cshell aliases
   Shell variables
   Shell scripts
   More information


     As mentioned in other lessons, a shell is "just" a program, but what a 
program!  It has to hide many of the gruesome details of the underlying bare
operating system and give the user a way to easily get his or her work done.
It also has to enable users to run UNIX commands, to edit files, compile
programs, run programs, and interrupt them if they go awry.

     Probably the reason why the term "shell" was chosen for this important
program is because it wraps around the inner part of the operating system,
often called the "kernel", hiding the messy details of UNIX system calls,
signals, and files.  Every operating system has to have one or more ways to
enable users to get at it, but the concept of separating the shell from the
kernel of the operating system was new to Multics, the failed progenitor of 
UNIX.  Ken Thompson saw the value of the removable, replaceable shell and 
carried it over into UNIX.

     The first shell, one that is still used, is the Bourne shell, written by
S.R. Bourne.  It can be started by typing the command

     % sh

The Bourne shell's default prompt is the dollar sign.  Like all UNIX shells, it
can be exited by pressing CONTROL-D or typing the special command:

     $ exit

     The Cshell was pioneered in Berkeley UNIX and has so many neat features 
that it is now widely used.  Its command name is "csh".

     Another shell that is rising in popularity is the Korn shell, abbreviated
as "ksh".  It builds on the nice features of the Cshell, adding things like
script functions and a nicer history mechanism.

     There are many other shells, some specially written at various colleges and
universities.  Some shells restrict the user to only a small subset of commands
so that they cannot access certain parts of the system in a secure UNIX environ-
ment or when they are guests on other people's computers.

     A newer kind of shell is the graphical user interface, which is not a shell
in the traditional sense, but which still surrounds the bare operating system,
allowing users to get work done.  One such interface is X windows.  However, 
in most of these interfaces, users still interact with UNIX through traditional
shells in the windows they create on the screen.

How shells work

     The standard method of execution in a traditional shell is called the
read/evaluate/print loop.  The shell does these steps:

     1.  Prints the prompt and waits for user input.
     2.  User types in something, possibly editing the line if there are
         mistakes.  When done, the user presses RETURN.
     3.  The shell interprets what the user typed in as a command or
         program and executes it.
     4.  The command executed may print some output, which is printed on
         the user's terminal, or it may ask the user for additional input.

There are a number of subtleties in the above.  For example, how does UNIX
know what program to run when the user types in something.  The shell program
breaks up the input line into words, which are sequences of non-blank charac-
ters separated by blanks.  The first word is always the command name, which the
shell uses as the name of an executable program to run.  The way that UNIX
finds the executable program is discussed later in this lesson under command

     Another subtlety is that the output may not go to the terminal, but can
rather be redirected into a file or even into another program.  This is
discussed later under redirection and pipelines.

     If a program requests input, it may get the input characters from the user
terminal, or from a file or even from another command.  This is handled by
input redirection.

     What happens to the shell program while the program is running?  It goes to
sleep, in UNIX terms, while the program executes.  After the program finishes,
it sends a wakeup signal to the shell, along with a return status value.  In 
this way, the parent shell is not harmed or killed by any malevolent or errone-
ous action of the program.


     History refers not to dry old subjects that you are forced to take as Area
IV requirements, but rather a way of remembering and recalling UNIX commands
that you previously executed.  The Cshell pioneered inclusion of history into
UNIX shells; the Bourne shell still does not have it.

     As you type in commands, they are copied into memory so that you can later
re-execute them.  Even after you log off, these commands are copied to a file
so that you can redo them tomorrow or later.

     To see the commands that you have entered so far, simply type

     % history

Each command has a number, which can be used to recall it.  For example, if
history shows the following

   384  man sort
   385  pwd
   386  ls
   387  vi shell
   398  cc monster.c -ltermcap -lcurses -lm -o monster_game
   389  sp shell
   390  clear
   391  help
   392  vi monster.c

and you want to redo the "cc" command, then simply use the exclamation mark,
also called "bang", with the command's number:

     % !398

and the Cshell will cause it to be re-executed.  Most people use history to
re-execute commands that would be too tedious to retype in, like the above.

     Another way to redo the cc command would be to give an unambiguous prefix 
of it:

     % !cc

The Cshell searches backwards in its memory of commands for the most recent 
command that starts with "cc" and redoes that.  

     A shortcut to simply re-executing the last command is "bang bang:"

     % !!

This is handy if you need to do a command repeatedly like run a.out again and
again.  As a convenience, the Cshell always shows you the command before it 
re-executes it.

     Another common thing to do is to make a change to a command and then 
re-execute it, especially if you made a typing error and want to try it again.
You can specify that the last command is to be edited and re-executed by using
the caret character, ^.  Surround the part that is to be changed by carets
and then follow it with the substitution:

When the Cshell sees the caret, it knows this is an edit/re-execute operation.

     For example, suppose you mistype the following:

     % cc monstre.c -ltermcap -lcurses -lm -o monster_game

And you realize that "monstre.c" should have been "monster.c".  Rather than 
retype the whole command, do the following:

     % ^monstre^monster

and the Cshell will fix it and re-execute it for you.  Actually, you need only 
give the smallest part that will identify the mistake.  For example, you could 
have done

     % ^re^er

and the Cshell would have found the first occurrence of "re", substituted it
with "er" and re-executed it.

     You can even edit a much earlier command by first having the Cshell print
it.  For example, suppose the the mistyped cc command was 5 or so commands
back.  Using "history", you see that its number is 398.  First recall it
by using !368, but to avoid having it be re-executed right away, follow it with
:p to print it.  This makes it the last or most recent command so that you can 
use the caret to edit it:

     % !398:p
     % ^re^er

     When you log out, your history of commands is appended to a file in your 
home directory called .history.  Whenever you log back in, the contents of this
file are loaded into the Cshell memory so that you can re-execute previous 
commands as though you had never logged out.

     The number of commands that are saved can be set by setting a shell
variable in your .cshrc file in your home directory:

     set history=100

This says to save only the last 100 commands.  The oldest command is erased
when a new one is entered.

The command path

     Most UNIX commands are actually just programs.  For instance, "ls" is a 
program that reads the table of contents from a directory file and formats it
so that you can understand what it means.  Its compiled executable file is in
/bin/ls, as are many of the other common commands, like cat, ps, and grep.

     A few commands are not really programs, but merely subroutines inside the
shell.  They are called built-in commands and include ones that are intrinsic to
the shell, like "cd",  which changes the current working directory, stored in
the shell's memory.  Other built-in commands are those that deal with shell
programming.  Here's a quick list of Cshell's built-in commands:

     alias, unalias, bg, fg, jobs, kill, cd, echo, exec, exit, foreach, end,
     goto, history, if, then, else, endif, login, logout, popd, pushd, rehash,
     set, source

Because they are part of the shell program, you will not find files for these 
in the /bin directory.

     Sometimes you wish to run program files as commands from your own 
directory, or the system administrator may have put programs in other places.
Generally, /bin is reserved for the essential commands, so additional commands 
are put in other directories.  But how does the shell know where to find the 
executables when you type in a command's name if they are not in /bin?  It does
this by means of the command path.

     There are a number of variables in the shell which hold crucial infor-
mation, and one of these is $path.  It contains a list of directories which are
searched every time you type in a command that is not a built-in shell command.
If UNIX finds an executable with the same name, then it creates a child shell,
runs the program in that child shell after putting the parent shell to sleep,
and then awakens the parent when the child finishes.

     You can see your path by doing

     % echo $path

Since $path is a shell variable, it must start with a dollar sign.  Echo is
a built-in shell command that prints out its arguments after substituting
values of variables.  You will see something like

    /mnt1/dept/meyer /mnt1/dept/meyer/bin /mnt1/dept/meyer/scripts 
    /usr/local/bin /usr1/local/bin /usr/lang /usr/ucb /bin /usr/bin /usr/new 
    /usr/games /usr/openwin/bin ./bin .

This is sometimes called the search path because UNIX searches the directories
in this order in order to find an executable that it can run when you type
something in.

     Notice that all these directories are spelled out in full using absolute
path names, except for the last two items which are relative to the current
directory.  The final item, ., means to look in the current directory for the
command if it is not found first in any other directory.  Many people also put
executables into a bin directory, which is what ./bin means.  There could be
bin directories in many other directories.

     You can change your path by using the set command.  If you want to make a
temporary addition to your path, do something like the following:

     % set path=($path /usr/ucb/games)

if /usr/ucb/games is the directory that you wish to add.  Most people do not 
change their path often, so they put the set command in their .cshrc file in
their home directory.  Here's an example:

     set path= ( ~ \
             ~/bin \
             ~/scripts \
             /usr/local/bin \
             /usr1/local/bin \
             /usr/lang \
             /usr/ucb \
             /bin \
             /usr/bin \
             /usr/new \
             /usr/games \
             /usr/openwin/bin \
             ~/Perl/bin \
             ~/LANGS/SCHEME/scheme-2.5 \
             ./bin \
             . )

The backslashes are actually continuation symbols in Cshell language.  Remember
that ~ stands for your home directory.

Running programs in the background

     Occasionally, you may have a long running task you need to do but you do 
not want to sit at a terminal waiting for it.  UNIX allows you to run more than
one program at a time, with all but one of them being in the "background".

     To run a program in the background, just type the command or program name,
followed by an ampersand.  Here's an example, compiling many C source files to
make a program:

     % cc *.c -o monster &

Normally, your terminal's cursor would have blinked stupidly at you while you 
were waiting for cc to get through all the C files.  Using the background 
method, you get a new Cshell prompt immediately and start doing something else.
You can even put many more than one command in the background.

     After you start a command in the background, UNIX prints out the PID of
the child process, which is the Process IDentification number.  This number can
be used later to find out about or to kill the process.  To check up on your
processes, use the "ps" (process status) command:

     % ps

This prints out a list, looking something like the following:

       171 p2 R     0:00 ps
     27318 p2 S     0:00 -sh (csh)
       137 p2 R     3:05 cc *.c -o monster

The cc command has a pid number of 137, and it has used up 3 minutes and 5 
seconds of CPU time so far.  Its status is Running and it was started from
terminal "p2" (actually "ttyp2").  To kill it, do:

     % kill -9 137

The -9 is a signal number, the highest possible, which cannot be ignored by the
program.  This is a sure-fire method of stopping a program.  If you do "ps" 
again, you will not see the cc command there.

     Background processes are also useful if you want to start up a command, 
then log off and go away.  Once you start a command in the background, you can 
log off, and UNIX will continue running it.

     The opposite of "background" is "foreground" and in UNIX, the foreground
is the space where only one process can be running at any one time, the one you
started without the &.  This is where we have been running the programs up till

     What happens to input and output if a program is running in the background?
UNIX has two different answers.  If a program or command in the background
requests input from stdin (standard input), then UNIX kills the program or
command and prints an error.  This is logical because there would be no way to
tell UNIX where your keyboard input should go.

     If the background program or command writes to stdout or stderr, the two
standard output and error files, then the characters it writes are immediately
sent to the terminal, unless redirected.  This is not necessarily fatal, but
it could interrupt what you are doing or intermix its characters with output 
from the command you are running in the foreground.

     The moral of this story is that if you are running something in the back-
ground, you should ensure that redirection is used for either input, output or 

     Here's an example of something you would definitely want to use with output
redirection.  Suppose you wanted a list of all the files in your UNIX system.
This is going to take some time and it will generate lots of output.  Since ls
never asks for input, it is safe to ignore requests for input, but you must
send the output into a file, or you will get an unreadable mess when you try to
do another command in the foreground while ls is running.

     % ls -lR / > allfiles &

The trouble with the above example is that whenever ls hits a directory that is
not public, it will print an error message.  But the output redirection is only
for stdout, so all stderr messages will still get written to your screen, which
could mess you up if you are editing a file, for example.

     There is a way in the Cshell to redirect both stdout and stderr to a
file: use >&.  Here's what you would do:

     % ls -lR / >& allfiles &

The & in this case could be thought of "both stdout AND stderr" since & is
often an abbreviation for the word "and".

     This brings up an interesting question: why did Thompson choose & for
the background symbol?  The reason is NOT that he was running out of symbols
to use, but rather than he envisioned that a user would type in several
commands in one line, separating them with the ampersand, meaning "do this
AND do that at the same time".  This is just a historical footnote, as no one
uses the background ampersand this way anymore.  Here's an example, though:

     % a.out < infile > outfile & ps

Job control

     One drawback of background processes used to be that you either had to
start the process in the background (with the &) or in the foreground (without
the &) and, once started, it could not be moved from one place to another.  
For example, if you started a long running command, but didn't know it would 
take so long, you had to kill the current command and restart it in the 

     With Berkeley UNIX, this problem vanished because a running job could be
suspended and then moved to the background.  To suspend a running program,
type CONTROL-Z (remember that CONTROL-C will kill a running program, which is
not what you want now.)  UNIX responds by saying "Stopped".  To put the 
program in the background now, do

     % bg

If you want to bring a background job to the foreground, first type

     % jobs

to get a list of the programs.  They will have numbers beginning with 1 in
front of them, and it will say "bg" or "fg" and whether it is running or
stopped.  To bring job #1 to the foreground, do

     % fg 1

Likewise you can kill a background running or stopped job by using kill with
one of these numbers preceded by a percent sign:

     % kill %1

If the job is running in the foreground, then you must use CONTROL-C to kill it.

     For some reason, Berkeley UNIX changed the terminology a bit.  Instead of
calling a running program or a command a "process", they called it a "job",
hence the term "job control".  Don't be fooled -- a job is just a program or
command.  (Commands are just programs, too.)

     Job control, which is not available on some older UNIX systems that have
only the Bourne shell, allows you a way to temporarily suspend a running job
without killing it.  Just do CONTROL-Z without putting it into the background.
It simply stays in the job list, stopped, until you put it either in the
bg or fg.  Unfortunately, the Cshell will not allow you to log off if there
are stopped jobs, so this is not a way of suspending a program between logins.

Wildcard characters

     Unix uses a host of special characters called wildcard characters to enable
you to affect many files at once.  All of these special characters are trans-
lated by the shell into sequences of characters, usually a list of file names.
     The asterisk (*) is translated into any matching characters.  For example, 
in a particular directory if you do
     % rm x*
then any file whose name begins with the letter x will be removed. The asterisk
stands for any string of 0 or more characters. Thus, the names x, xyz, xxx, x47
all match x*.
     To cat all files which begin with the letter a and end in the sequence
dit, do
     % cat a*dit
This would match file names such as adit, a.dit, abcdit, and addit.
     The asterisk by itself stands for any sequence of characters, and is there-
fore very dangerous.  The following command will remove ALL files in the current
     % rm *
This does NOT match any file name that begins with a period.

     Other wildcard characters include the question mark, which is like the
asterisk, except that it matches exactly one letter or digit.  Here's a way to
remove all files that start with a period and are at least 3 characters long:

     % rm .??*

The period matches the leading period, the two question marks match two sub-
sequent characters (one each), and the final asterisk matches 0 or more charac-

     The tilde ~ is translated into your home or login directory, while ~user
turns into the home or login directory of user "user".

     UNIX has a way of specifying a set of characters.  The square brackets 
specify a set or a range of characters which can match a filename.  For example:

matches files arb, axb, and azb.  For example, if you wanted to look at the head
(first 10 lines) of each file whose name had this pattern, you would do

      % head a[rxz]b

If arb and azb existed, but axb did not, UNIX would just show the head of
arb and azb.

If you wanted to match a file that had several r's, x's and z's between a...b,
you could put an asterisk after [rxz]* as follows:

the asterisk, in this case, meaning 0 or more occurrences of the pattern that
preceded it, namely the set of single characters [rxz].

     You could also specify a range of characters, using a dash.  The following
would print out chapters 0-9 of your latest book:

     % lpr -Psp chap[0-9].dit

such as chap0.dit, chap1.dit, etc.  Again, the asterisk could be used to specify
that there were several digits in the chapter number, such as chap12.dit.

Command pipelines

     Another form of redirection is the pipe, symbolized by the vertical bar |.
Note that this is NOT the exclamation mark, nor are they interchangeable since
the exclamation mark is used for history.

     UNIX promotes the use of small, simple but flexible tools that can be
combined in many unanticipated ways to perform complex tasks, obviating the
need for hundreds of nearly identical features on every command.  Input and
output redirection helps achieve this goal as well as the pipe.  In fact,
the pipe is a form of redirection.

     Many commands read their input from the special file stdin (standard input)
and write their output to stdout (standard output).  These can be changed from
being the user's terminal to a file by use of the < and > symbols, respectively.
The pipe allows us to bypass an intermediate file and directly send the output
of one command into another command as its input.  Here's an example.

     If you have a lot of files and you want to do a long listing using "ls -l"
the output will almost surely scroll off your screen.  To prevent losing the
top part, you could redirect the output to a file, and then use "less" to view
the file, or even "vi".  However, this means you have to think up a filename
and do two separate commands:

     % ls -l > /tmp/myfile
     % less /tmp/myfile

In this example, the /tmp directory was chosen as the place to put the temporary
file since nothing in this directory is permanent and it is cleaned regularly.
However, this is too much work.

     Another possibility would be to add an option to the "ls" command, like
MS-DOS does.  For example, in MS-DOS you could do "dir /p" where the /p is the
page pause option.  But this means that every single UNIX command must have an
option to let the user pause the output.

     UNIX's method is much cleaner.  You simply redirect the stdout of ls to
the stdin of less, which is indicated by separating the two commands with a
vertical bar.  (Although computer users are not supposed to be curious or ask
about where the mystical symbols come from which they use every day, the
designers usually had some down-to-earth origin.  The pipe symbol may or may 
not have been meant to symbolize the pipe holding the data flowing from one 
command into the other, but in any case, it is the wrong direction!)

     Here's how you would use a pipe to slow down the output of "ls -l":

     % ls -l | less

No input filename needs to be given to "less" since it is reading from stdin.
This is true of many UNIX commands, that they can either take a file name or
stdin.  Wc is a similar command:

     % wc bigfile

Wc can count words, lines and bytes in a file, or in standard input.  The 
following counts how many users are logged in:

     % who | wc -l

The -l option on wc tells it to output only the count of lines.

     We call the sequence of commands connected by pipes a pipeline because
data flows from one command to another in a single direction, ultimately
appearing at the terminal screen.

     You can even have longer pipelines with three or more commands.  An example
would be if you had a book that consisted of several numbered chapters, and you
wanted to check the spelling.  It is better, in one sense, to clump together the
files before using "spell" so that it will only count each misspelled word once.
The cat command can be used to concatenate (string together) several files.
However, the output of spell may be long, so you will probably want to use less
to view it in a controlled fashion.  Thus:

     % cat chap* | spell | less

You may also want to view the output as well as capture it in a file.  Tee is
the command that captures data flowing from stdin to stdout into a file.

     % cat chap* | spell | tee misspellings | less

Notice that less is still used because tee does not slow down the output.

     Each command in a pipeline, like the examples shown above, runs simultan-
eously.  Unlike UNIX, MS-DOS, which also has pipelines and redirection, runs the first command to completion before the next one starts, saving all the results in temporary files.  Instead, UNIX uses a hidden area of memory to store part of the results.  When this fills up, UNIX lets the next command in the pipeline access the memory in order to process it. For each pipe symbol in a pipeline, there will be a separate hidden memory area.

Command substitution
     Occasionally, especially in shell scripts, you want to evaluate a UNIX
command and use its output as part of another command.  The shell allows you to
do this by surrounding the other command in backquotes (not forward or regular
quotes).  UNIX does this other command first, substituting the output where the
backquoted command was found.  Here's an example:

     % echo There were `ls | wc -l` files
     There were 33 files

The outer command, echo, is just a way of printing something, usually in a shell
script.  When the shell sees `ls | wc -l` in backquotes, it stops the echo
command and evaluates the ls pipeline, getting the number of files in the
current working directory.  This output, a number, is substituted into the 
echo command just as if the following were typed:

     % echo There were 33 files

and the resulting output is shown.

Cshell aliases

     Aliases are a way of setting up alternate command names.  For example, if
you are used to MS-DOS and you keep typing "dir" instead of "ls" to list your
files, you can create an alias:

     % alias dir ls

Now when you type in "dir", UNIX substitutes the alias.  This only works for
aliases at the beginning of command lines.

     Another use of aliases is to completely substitute one command for another.
Many people change "rm" so that it merely moves files to a trash directory,
rather than remove them from the system, so that the files can be recovered if
needed later.  Here's an alias to do this:

     % alias rm 'mv \!* ~/.TRASH'

This alias is rather complicated because there must be a way to append the
string "~/.TRASH" at the end of the substitution.  The string \!* stands for
whatever followed "rm" on the original command.  To make this clear, consider
the user typing in the following:

     % rm *.c *.h a.out

The Cshell looks up "rm" in its alias list and finds the alias given above.
It then replaces "rm" with "mv", the move command.  Then it takes what followed
the "rm", namely "*.c *.h a.out", and inserts this where \!* was in the alias, 
finally following it with "~/.TRASH".

     USER:     rm            *.c *.h a.out
     PATTERN:  mv            \!*                 ~/.TRASH
     RESULT:   mv            *.c *.h a.out       ~/.TRASH

If you still want to use the "real" rm command, you can always refer to it by
using /bin/rm.  In fact, you probably want to make another alias up to empty
the trashcan:

     % alias emptytrash '/bin/rm ~/.TRASH/*'

     Most people put aliases in their .cshrc files in their home directories so
that they do not have to type in aliases at the beginning of each session.

     One last word about aliases.  Some people arrive at UNIX after learning to
use another type of computer and operating system, and naturally they remember
the old commands better than UNIX.  Therefore, they may tend to create many
aliases so that they can use the old command names instead of the UNIX ones.
Though this is permissible, and even laudable to some degree, it fosters the
illusion that one is still working in the old system.  It is generally impos-
sible to make the aliases handle the options and arguments so that they truly
act like the old system, which means that the user has to learn the options and
arguments of the UNIX commands anyway.  Therefore, it is probably not a good
idea to create aliases to fool yourself into thinking you are using another
operating system.  What you end up with is neither UNIX nor your old system,
just a confusing mess that no one but you can understand.  When in UNIX-land,
do as the UNIX gurus do!

Shell variables

     Shells, including the Bourne, C, and Korn shells, provide ways of storing
numbers and character strings in their memory in the form of variables, very
much like variables in a programming language.  However, all variables in
shells have names that begin with a dollar sign in order to distinguish them
from commands.

     To put a value in a variable, "set" is used in the Cshell, while different
syntax is used in the Bourne shell, which will not be discussed herein.

     % set x=/usr/include/sys

You can recall the value of a variable by using echo:

     % echo $x

Better yet, the variable's value can be used in a variety of settings, for 

     % ls $x
     % vi $x/stream.h
     % cp $x/stat.h ~

The variable $x in the examples above was used to shorten the name of files
when the user was going to work with /usr/include/sys.  This is one of many
uses of shell variables.

     If you forget what shell variables you have set, just do

     % set

and the Cshell will print out all those that are currently assigned.  There are
a number of built-in shell variables, many of which are used only for shell
scripts.  One of these is $cwd, which is the current working directory, pre-
pended to every relative pathname that you enter.

     You can reassign a shell variable at any time, or you can unset it so that
it has no value:

     % set x=

The above just gives the null string to the variable as its value, while

     % unset x

actually deletes it from the Cshell's memory.

     Another common use of shell variables is to change the prompt, since that 
is just a built-in variable:

     % set prompt="Hello> "

If the character string has a special character like a blank or greater than
sign (which is also the output redirection symbol) in it, it must be surrounded
by double quotes as shown above.

     If you put the string "\!" in your shell prompt, then the Cshell prints out
the command number, so that you can tell how many commands you have issued since
you logged in.  Here's an example:

     % set prompt="`hostname` \! % "

This also executes the UNIX command "hostname" which prints out the name of the
computer on which this is running, in case you move to a different school or
UNIX computer.

     Shell variables can even be used for commands:

     % set lsa="ls -l"
     % $lsa

"lsa" becomes an alias for a command, but true Cshell aliases are better to use
because of the internal substitution that is possible, as shown by the rm
example above.

Shell scripts

     If you find that you are doing the same commands over and over, and they
are long and hard to type in, you could form an alias, or set a shell variable.
But you can't make decisions inside aliases nor can your sequence of commands
be very long; shell scripts provide a way to bundle together commands.

     In case you are familiar with MS-DOS and the world of IBM PCs or PC clones,
shell scripts are really just batch files, those files whose names end in .BAT.
They serve the same function in MS-DOS as shell scripts in UNIX.  In fact, it is
no accident that MS-DOS looks like UNIX, since the designers, Microsoft, Inc.,
modeled its operating system for the IBM-PC on UNIX, way back in 1981.

     A complete tutorial on shell scripts exists, which you should read if you
are interested.

More information

     Probably the best book to consult for more information on the shell and
using UNIX is:

     "An Introduction to Berkeley UNIX" by Paul Wang, Wadsworth Pub. Co.,

There is an extensive chapter on the Cshell, and even some information on the
Bourne shell.  Another chapter is devoted to writing shell scripts.  It is a
rich book, well written, with lots of good examples.

     Other good books are discussed in the bibliography tutorial.