CS 111 – Project 1 – Spring 2005

Shell Program


Relevant text:

Pages 67-82 of Kernel Projects for Linux by Gary Nutt.


Description:

A shell (eg. Bash, tcsh, ...) takes a command from the user and executes it. Most commands have a corresponding “executable binary”. For example, the ls command has an executable binary:

/usr/bin/ls.

Your project is to implement a Linux shell in C that supports Input/Output redirection, multiple pipes, sequential execution, conditional execution and backgrounding.

In addition, your project is to include one feature from the following list.

  1. pattern matching

  2. parenthesis


Due date:

Friday 4/29/2004 by 5 a.m.

Submission instructions: TBA on CourseWeb.


Project Details


Output redirection:

Your shell should be able to use files as input or output for commands.


The redirection symbol '>' should be used to redirect output. For example:

$ls > filelist.txt

This command line will run the ls command and use the file filelist.txt to write its output (instead of the standard output, which is by default the terminal).

If the file already exists, your shell should return an error message and should not execute the command.


The redirection symbol ‘<’ should be used to redirect input. For example:

$sort < filelist.txt

This command line will run the sortcommand and use the file filelist.txt to read its input (instead of the standard input, which is by default the terminal).


Pipes:

Your shell should support pipes. The pipe symbol '|' should be used to connect the standard output of one command to the standard input of another command. When a user runs command A and uses the '|' (pipe) symbol to pipe the output of A to B, the output of A does not get written to the standard output (usually the screen), but instead gets written to the input of B.

For example:

$ls | sort

The ls command lists the contents of the current directory. In this case, it would not print on the screen, since the output of ls is piped to sort (which sorts the input alphabetically). After the output of ls has been sorted by sort, the sorted list of files appears on the screen.

Note that typical Linux shells support multiple pipes, such as ($A | B | C)

Your shell should also accept more than one pipes and should support a combination of Output redirection and pipes.

For example:

$ls | sort > sorted_filelist.txt

This command should pipe the output of ls to the input of sort, and redirect the output of sort to the file sorted_filelist.txt.

Note that Output redirection is always associated with the command it follows and NOT with the whole command line.


Sequential execution

In this case, the symbol ‘;’ is used to indicate sequential execution of commands.

For example:

$ ls ; ps ; cat testfile.txt

This list of commands should result in sequential execution of the three commands. The ps command should execute only when the ls command finishes execution. The shell prompt is returned only when the last command in the command line has finished execution.


Conditional execution

Your shell should support the symbols ‘&&’ and ‘||’. These symbols are used to indicate conditional execution of commands.

Example:

$ ls && ps

In this case the second command ‘ps’ will only execute if the first command succeeded (i.e. the return value of the command is 0).


Example:

$ grep || ps

In this case the second command ‘ps’ will only execute if the first command failed (i.e. the return value is non-zero) In this grep will fail because no arguments were supplied, so the ‘ps’ command will be executed.


Background execution

In this case, the symbol ‘&’ is appended to the end of the command, causing the command to be executed but not to wait for the command to exit.


Example:

$ ls /* > filelist.txt &

In this case the command will execute, but the shell will not wait until the completion of the ls command.


Filename matching

Implement pattern matching (*,?) operations in the shell.


The '*' character matches zero or more characters. The '?' character matches exactly one character.


Example:

suppose that there are files named 'a.txt' 'b.txt' 'file.txt' and 'file.c' in the current directory

$ ls

would return

a.txt b.txt file.txt file.c


With filename matching implemented:

$ ls ?.txt

would return

a.txt b.txt


$ ls *.txt

would return

a.txt b.txt file.txt


Note that when used in quotes, the special meaning for '?' and '*' is ignored:

$ ls “?.txt”

would return

?.txt: No such file or directory


Parenthesis

Parenthesis are used for grouping commands. It provides a mechanism to group a list of commands to be executed as a unit. When commands are grouped, redirections may be applied to the whole command list.

Example:

( ls; ps ) > ls_ps_output_combined.txt


In this example the output of both commands is redirected to ls_ps_output_combined.txt


Other notes:

Your shell prompt should be “cs111_spring05$

Only open a file for output redirection if the command is valid and going to be executed.

Your shell should use the current $PATH environment variable to search for commands. Note that some variations of the system call 'exec' use the $PATH variable by default. See the man page for exec for details.

Your shell should handle certain error cases gracefully and display appropriate error messages, such as:

• “No such file or directory” when a file does not exist, such as when redirecting for standard input.

• “Permission denied” when a file fails to open for input redirection.

• “Syntax error” when the command line is not recognized as legitimate input.

• “Command not found” when a command is not found in the $PATH

After starting your shell, users should be able to execute commands like:

find /bin -name ls -print

cd /etc

ls -al /bin > lsout.txt