讲解shell、讲解Assignment cpe 357 SHell程序
- 首页 >> OS编程Assignment 5
cpe 357 Winter 2018
As soon as we started programming, we found to our surprise that it wasn’t
as easy to get programs right as we had thought. Debugging had to be
discovered. I can remember the exact instant when I realized that a large
part of my life from then on was going to be spent in finding mistakes in
my own programs.
-- Maurice Wilkes, designer of EDSAC, on programming, 1949
— /usr/games/fortune
Due by 11:59:59pm, Wednesday, March 7th.
For this assignment you may work with a partner1. Be sure both names appear in the README.
Program: parseline
Shell command-line parsing:
This assignment is to do the command-line parsing necessary for the Minimally Useful SHell
(mush) that will be the subject of Asgn 6.
The Minimally Useful SHell (mush) has nowhere near the functionality of a full-blown shell like
/bin/sh or /bin/csh, but it does support both file redirection and pipes. parseline is a subset
of the shell that prompts for and reads a single mush command-line and parses it into a list of
commands showing the inputs, outputs, and arguments of each.
Details
The grammar of mush is fairly simple:
• A command (pipeline stage) consists of a command name followed by its arguments, separated
by whitespace.
• A command’s standard input and standard out can be redirected from or into files via the use
of < (standard in) and > (standard out). The filename for the redirection is the single word
following the redirection symbol. A missing name names constitutes an error.
The redirection symbol and filename are not considered part of the command name or argument
list and are not included in the count of arguments.
• A pipe (|) connects the standard output of one command to the standard input of the following
one. For example, “ls | sort” makes the output of ls the input of sort. A series of
commands separated by pipes is a pipeline.
• You can assume that ’<’, ’>’, and ’|’ will appear as words by themselves with space around
them. That is, you don’t have to deal with “ls b<a|more”. In addition, the characters ’<’,
’>’, and ’|’ are not valid filenames, so “a.out > < a” is an error, not the creation of a file
called “<.”
Note, however, that redirections will not necessarily appear at the end of the command line.
That is, “ls > out a b” would be a legitimate command to list the files “a,” and “b” into
the file “out”.
1This will have to be a partner for both this assignment and Asgn 6.
1
In order to make the process easier, you may apply certain limits to the command line structure.
These limits must be documented in your README file, and command-lines that are rejected for
exceeding limits must be reported as errors.
Command line length: at least 512 bytes
Commands in a pipeline: at least 10
Arguments to a command: at least 10
The fact that these maxima2 exist will allow you to avoid the use of dynamic data structures.
My initial version of this program did not have a single call to malloc() in it. (The current version
does.)
Error Handling
parseline must identify and report malformed commands. This includes:
• malformed redirects. For example, “a.out < ” doesn’t specify the name of the file for redirect
while “a.out < a < b” has two input redirects.
• ambiguous inputs or outputs. For example, in the pipeline “ls | sort < foo”, the input to
sort is specified to be two different things.
• command-lines that exceed any limits imposed (above).
Output
The purpose of parsing a command line is to identify the various components of each command so
that each can be launched appropriately. On a Unix system, one needs to know where the input will
come from, where the output will go, the number of arguments on the command line (not including
any redirection commands) and the values of those arguments.
In order for this program to be efficiently graded, it is important to adhere to the output format
specified below.
Error Cases When there is an error in one of the commands in the pipeline, parseline prints
an error message an exits with nonzero exit status. If there are multiple errors on a line, it prints
the the first one it encounters. Possible errors are shown in Table 1.
Valid Cases For syntactically correct pipelines, parseline should print out a description of
each stage of the pipeline in the form given below. For the sake of parseline, the first stage of a
pipeline will be stage 0. The required form of the output:
1. a header that identifies the stage number and shows the portion of the command line that
corresponds to that stage, in quotes. This header should follow a blank line and have the
following form:
--------
Stage n: "<command line>"
--------
Example:
--------
Stage 0: "ls a b c "
--------
2The phrasing here is a little awkward. What it means is that you may apply a maximum limit for each of these
properties, but the value of your maximum must be at least as big as that given in the table above. That is, you can’t
define the maximum command line length to be 0 and be done.
2
Cause Message
command line length limit exceeded command too long
pipeline has too many elements pipeline too deep
an individual command has exceeded
the limit on arguments
cmd: too many arguments
a pipeline has an empty stage, e.g.,
“ls | | more”
invalid null command
a command either has more then one
input redirection character (’<’), or
the input filename is missing
cmd: bad input redirection
a command either has more then one
output redirection character (’>’), or
the input filename is missing
cmd: bad output redirection
a stage has both an input redirect and
a pipe in
cmd: ambiguous input
a stage has both an output redirect
and a pipe out
cmd: ambiguous output
Table 1: Possible errors that mush will encounter
2. a specification of the input for the stage which will be one of:
a filename, if redirected
“original standard input”
“pipe from stage n”
Example:
input: original stdin
3. a specification of the output for the stage which will be one of:
a filename, if redirected
“original standard output”
“pipe to stage n”
Example:
output: pipe to stage 1
4. the argument count (argc) for the stage.
Example:
argc: 4
5. the arguments strings for the stage with extra whitespace trimmed off, in quotes, commaseparated.
Example:
argv: "ls","a","b","c"
3
Tricks and Tools
Remember, parsing is always harder than it looks. Be sure to give some serious thought to your
approaches and data structures before diving in. There are many library routines and system calls
that may help with implementing parseline. Some of them are listed in Figure 1.
sscanf()
strchar()
index()
strtok()
strpbrk()
etc.
The string functions, defined in string.h and strings.h, are helpful
for parsing strings
isspace()
etc.
One of many functions defined in ctype.h for text processing. Very
useful.
Figure 1: Some potentially useful system calls and library functions
A few thoughts:
• You can find out the number of stages in the pipeline by counting number of times the pipe
character (|) appears and adding 1.
• You only need to report the first error you find, so you can abort processing once you find one.
• Be far-sighted about this. Read the specification for the full version of mush before starting
so you will know where you want to end up. You want to make design decisions you can live
with next week.
• Remember that although parsing looks easy it it harder than it looks. There are a lot of edge
cases.
Coding Standards and Make
See the pages on coding standards and make on the cpe 357 class web page.
What to turn in
Submit via handin to the asgn5 directory of the pn-cs357 account:
• your well-documented source files.
• A makefile (called Makefile) that will build your program with the command “make parseline”.
• A README file that contains:
– Your name(s). In addition to your names, please include your Cal Poly login names with
it, in parentheses. E.g. (pnico)
– Any special instructions for running your program.
– Any other thing you want me to know while I am grading it.
4
The README file should be plain text, and should be named “README”, all capitals with
no extension.
Sample Runs
Below are some sample runs of parseline. I will also place an executable version on the CSL
in ~pn-cs357/demos so you can run it yourself.
% parseline
line: ls
--------
Stage 0: "ls"
--------
input: original stdin
output: original stdout
argc: 1
argv: "ls"
% parseline
line: ls < one > two three four
--------
Stage 0: "ls < one > two three four"
--------
input: one
output: two
argc: 3
argv: "ls","three","four"
% parseline
line: ls < one | more | sort
--------
Stage 0: "ls < one "
--------
input: one
output: pipe to stage 1
argc: 1
argv: "ls"
--------
Stage 1: " more "
--------
input: pipe from stage 0
output: pipe to stage 2
argc: 1
argv: "more"
--------
Stage 2: " sort"
--------
5
input: pipe from stage 1
output: original stdout
argc: 1
argv: "sort"
% parseline
line: ls | | more
invalid null command
% parseline
line: ls < a < b | more
ls: bad input redirection
% parseline
line: ls < a | more < file
more: ambiguous input
% parseline
line: ls < a < b > c > d
ls: bad input redirection
%
6