






			 csci-e215
		 Assignment 5: small shell


Introduction

A  Unix	 shell	is  a  tool that allows users to manage pro-
cesses.	 Using a shell, a person can run  programs,  control
input and output, and create pipelines.

Unix  shells  do more than launch programs.  Most shells are
comprehensive programming languages.  The shell	 programming
language  includes  variables (local and global), functions,
and a full range of control flow syntax, including if state-
ments and while loops.	Programs written in a shell program-
ming language are called shell scripts.

The sample shell developed in class implements about half of
the  features  of  a  typical  shell.	It runs programs, it
allows some control of environment variables, but it has  no
control	 flow,	nor does it allow one to use the shell vari-
ables in statements.

For this assignment, you will use the ideas and some of	 the
code  from class and the text to create a more sophisticated
shell.	By adding mechanisms to	 input	and  retrieve  shell
variables,  by adding an `if' statement, and by allowing the
shell to read scripts in addition  to  standard	 input,	 you
will give the shell enough structure to be programmed.


The Big Picture

In  its simplest form, a shell executes programs on request.
You type the name of a program, the shell creates a new pro-
cess,  and  then the shell runs the requested program in the
new process.  When the program ends, the shell wakes up	 and
awaits the next request.


The main loop for a shell is:

		set_up();		/* initialize things */
		while ( get_next_command() )
			parse_command()
			if ( ! built_in_command() )
				execute_command();


The Story So Far

In  the	 simple	 shells presented in class ( psh1, psh2, and
smsh1), `set_up' consists of initializing  the	environment.



		       March 31, 2001		      page 1





						     smallsh


The  `get_next_command'	 function reads a line from standard
input.	`parse_command' splits the input  line	into  white-
space  separated  strings.  The `built_in_command' operation
is a set of strcmp()'s and ifs and elses.  If the command is
a  built-in command, the shell calls an internal function to
do the work.  If the command is not built-in, then the shell
tries to fork() and execvp() it.


Where to Go from Here

There are lots of ways to expand a shell.  The textbook pre-
sents another approach to writing a shell.   It	 is  a	good
idea  to  understand the structure of that example.  By com-
paring the example from class to the one in  the  text,	 you
can  form  your own ideas about how you think a shell should
be organized.  You do not need to follow the basis from	 the
class  example,	 nor  do you need to copy the version in the
text.  There are many approaches to writing a  program,	 you
may  select any method that makes sense to you and meets the
requirements of the assignment.

For this assignment, you will write a  shell  that  includes
the  features  from the example in class plus specific addi-
tions.	The specific additions you will make are:


1)   Alternate Input   Smsh1 reads  commands  from  standard
     input.   This is the interactive mode: the user types a
     command, the shell executes it.   The  real  shell	 can
     also  read	 commands from a file.	This is the scripted
     mode: the user prepares a file that  contains  commands
     and  then	passes the name of that `script file' to the
     shell as a command line argument.	 For  example:	smsh
     file.of.commands

     Your program, smsh2, should check the command line.  If
     there is an argument, your smsh2 should use  that	file
     as	 a  shell  script.  When reading from a script, your
     shell should not print prompts before each line.


2)   The cd built-in   The shell executes the  change-direc-
     tory  command (cd) directly; it does not call a program
     to do this.  Be sure to understand why the shell cannot
     call a program to do this.	 Then add cd to smsh2.


3)   The  exit	built-in   The exit command causes the shell
     to exit.  If exit is  given  a  numeric  argument,	 the
     shell  passes  the value of that argument to the exit()
     system call.  The exit command is	particularly  useful
     in shell scripts.	Add this feature to your shell.




		       March 31, 2001		      page 2





						     smallsh


4)   Input   Implement	a  new	built-in command `read' that
     works sort of like the Bourne shell read command.	 The
     read  command takes one argument: the name of the vari-
     able into which the input is read.	 The shell reads one
     line  from	 standard  input  (not	from the script) and
     stores that line in the variable.	It therefore is	 the
     equivalent	 of C's gets() function, Perl's <STDIN>, and
     BASIC's input command.


5)   Variable  Substitution   Consider	 this	fragment:
     DIR=/usr/bin  ; ls $DIR $DIR.old	 it assigns a string
     to the variable DIR and  then  uses  that	variable  in
     another  command.	 The program `ls' sees the arguments
     /usr/bin and /usr/bin.old, not  the  strings  $DIR	 and
     $DIR.old.	 Add this feature to smsh2.  Where does this
     substitution take place?  During reading in  the  line?
     During parsing the line?  The way you add variable sub-
     stitution to your program affects the  design  of	your
     input and parsing sections.

     Think  through  this  carefully.  When the shell sees a
     dollar sign, it reads the following characters  as	 the
     name  of  a variable.  How does it know where the vari-
     able name ends?  The shell looks for  upper  and  lower
     case letters, digits, and the underscore.	Any sequence
     of those characters is a legal variable name,  as	long
     as	 the  first  character	is  not	 a  digit.  Thus, in
     $DIR.old the variable name is DIR .

     Your program, therefore,  will  consider  the  variable
     name  to  end  when  it encounters any character not in
     this set.	Make sure you modify the  assignment  state-
     ment  so  that  the user is not allowed to create vari-
     ables with illegal characters.


6)   Quoted Characters	 What if you want to include a	real
     dollar  sign  in your command, and you do not want your
     shell to try to substitute a variable value?   As	soon
     as you introduce special characters, you need to create
     a mechanism for un-specialing them.  The Unix tradition
     is	 to use the backslash in front of each special char-
     acter that you want treated `as is.'  Add this  feature
     to your shell.  More sophisticated quoting (using " and
     ') is not required.


7)   The if command   The hallmark of a programming language
     is	 the  if command.  Your shell should be able to pro-
     cess this:






		       March 31, 2001		      page 3





						     smallsh



		 echo Name to look up\?
		 read NAME
		 if grep $NAME $HOME/phonelist
		 then
		       echo there is the name
		 else
		       echo cannot locate $NAME
		 fi


     The word if is followed by a command and its arguments.
     The  shell runs the command normally and keeps track of
     the exit status of the command.  If the  command  exits
     with status 0, the lines after the `then' line are exe-
     cuted by the shell.  If the command exits with non-zero
     status,  then  the lines after `else' (if there be any)
     are executed.  The if command is terminated by  a	line
     consisting of the word `fi'.  The other keywords `then'
     and `else' must appear on their own  lines.   The	else
     clause is optional.  You are not required to get nested
     ifs to work, but it is interesting, and not that diffi-
     cult.


Getting Started

The sources from class are in ~lib215/lectures/lect09/5_Code
.   Various   supporting   documents   and   code   are	  in
~lib215/hw/smsh	 .   Copy what you want to play with to your
account and test out the  shell.   Get	smsh1  working	with
fork()	and  signal()  so it does the basic operations.	 Add
chdir() just to get started.  It is not tricky.

Think about variable substitution.  There  are	two  popular
approaches to this problem.

One  method  reads  the entire input line into an array then
calls a function to copy characters from that array to a new
one,  replacing	 each instance of $var with its value.	This
translation program also takes care of backslashes.

The other method performs variable substitution as part of a
wrapper to getc().  Usually, getc() returns the next charac-
ter from the current input stream.  Note,  to  support	item
(1), your shell will not just read from stdin.	It will read
from stdin or from a script.  This getc	 wrapper  will	read
the  next  character.	If it is a boring character, that is
neither backslash nor dollar sign, the	function  will	pass
that character to its caller.

On the other hand, if the character is a backslash or dollar
sign, the function will need  to  do  something	 fancier  in
order to return the next character to its caller.



		       March 31, 2001		      page 4





						     smallsh


Regardless of how you handle variable substitution, you need
to make sure you are splitting the input stream	 into  sepa-
rate arguments.


Plan out the `if' command implementation.  The command after
the word `if' run normally, but the exit status affects	 how
the shell processes subsequent lines.	You could use recur-
sion or you could keep some state variables.  In the  latter
case,  the  keywords  `else' and `fi' serve as state transi-
tions.


Your shell is a subset of the standard Bourne shell (sh), so
test how things are supposed to work under sh.

What to Turn In

  [1] Full source, Makefile, a clean gcc -Wall, and a sample
     run.   You	  must	 test	the   script   provided	  in
     ~lib215/hw/smsh/test.smsh	.  Other samples of its exe-
     cution are welcome.  Also, you need to turn in

 [2] Electronic version of source and docs.   Cd  into	your
     smsh working directory and
     type  ~lib215/handin smsh































		       March 31, 2001		      page 5


