If your code fork bombs on any autograde, then you will automatically fail this MP. Please make sure that your
fork() code is correct before committing your code for the nightly autograder.
If you use
system(), you will automatically fail this MP.
Now that you’ve completed your text editor, your mentor has assigned you a new task of implementing a simple Unix shell. The basic function of a shell is to accept commands as inputs and execute the corresponding programs in response. You will be provided the
format libraries for your use.
Your shell should operate like bash, which you are probably used to using. To execute multiple commands, your shell should run in a loop like this:
- Print a command prompt
- Read the command from standard input
- Print the PID of the process executing the command (with the exception of built-in commands), and run the command
Starting your shell
Your shell will support two optional arguments:
-f. Both options can potentially be used at once.
-h takes the filename of the history file. The shell should load in the history file as its history. Upon exit, the history file should be updated.
-f takes the name of the file to be executed by the shell. Your shell will run the commands in the file in sequential order. If the end of the file is reached without executing an exit command, then the shell should issue an exit command. See the following example file and execution:
When prompting for a command, your shell should print a prompt in the following format:
<pid> is the current process ID, and
<path> is a path to the current working directory. Note the lack of a newline at the end of this prompt.
Reading in the Command
The shell will read in a command from
stdin (or a file if
-f was specified).
Running the Command
The shell should run the command that was read in previously.
If the command is run by a new process, the PID of the process should be printed like this:
This should be printed before any of the output of the command is printed.
Your shell should store the command that was just executed. Every command should be stored unless otherwise noted.
Usually when we do Ctrl+C, the current running program will exit. However, we want the shell to ignore the Ctrl+C signal. The shell will not exit when a Ctrl+C signal comes.
Shell supports two types of commands: built-in and non-built-in. While built-in commands are executed without creating a new process, a non-built-in command MUST create a new process to execute the program for that particular command.
Words in a command will be separated by a single space, and there will be no extra whitespace anywhere in the command. Your shell does not need to support quotes (for example,
echo "hello there"). We will not test a blank line.
Changes the current working directory of the shell to
<path>. The starting point for pathnames that don’t start with
/ will be the current directory.
If there is an error, then the shell should print
<path>: No such file or directory.
Terminates the shell and saves the history of the shell if
-h was specified.
Prints for each command (in chronological order) its line number (0 indexed), a tab, the command itself, and a newline. Do not store this command in the history.
Prints and executes the nth command in history (chronological order), where n is a non-negative integer. Other values of n will not be tested. Note that the command run should be stored in the history. If n is not a valid index then print
Invalid Index, and do not store anything in the history. Note that this command is never stored in the history, only the command that is being referenced in the history. The following example assumes a fresh history:
Prints and executes the last command that has the specified prefix. Note that the command run should be stored in the history. If no match is found print
No Match, and do not store anything in the history. Note that this command is never stored in the history, only the command that is being referenced in the history. The following example assumes a fresh history:
For commands that are not built-in, the shell should consider the command name to be the name of a file that contains executable binary code. Such a code must be executed in a process different from the one executing the shell. You must use
wait() paradigm is as follows:
fork() a child process. The child process must execute the command with
exec(), while the parent must
wait() for the child to terminate before printing the next prompt. It is important to note that, upon a successful execution of the command,
exec() never returns to the child process.
exec() only returns to the child process when the command fails to execute successfully. In that case, shell should print (without the quotes): “xxx: not found”, where xxx is the executable name. For example:
Note that all non-built-in commands should be stored in the history, even ones that are invalid.
Some non built-in commands that you may try to see whether your Shell works as it should are:
Please read the disclaimer at the top of the page! We don’t want to have to give any failing grades.
A command suffixed with & should be run in the background. The shell should be ready to take the next command before the given command has finished running. There may or may not be a single space between the rest of the command and
&. For example,
pwd & are both valid. Additionally, since spawning a background process introduces a race condition, it is okay if the prompt gets misaligned as in the following example:
Grading, Submission, and Other Details
Please fully read details on Academic Honesty. These are shared between all MPs in CS 241.
We will be using Subversion as our hand-in system this semester. Our grading system will checkout your most recent (pre-deadline) commit for grading. Therefore, to hand in your code, all you have to do is commit it to your Subversion repository.
To check out the provided code for
vector from the class repository, go to your cs241 directory (the one you checked out for “know your tools”) and run:
If you run
ls you will now see a
vector folder, where you can find this assignment! To commit your changes (send them to us) type:
Your repository directory can be viewed from a web browser from the following URL: https://subversion.ews.illinois.edu/svn/sp16-cs241/NETID/shell where NETID is your University NetID. It is important to check that the files you expect to be graded are present and up to date in your svn copy.
Compile and Run
Because we have provided
Vector as precompiled archive
files, please make sure to work on this assignment on your student VM. We
can’t say what will happen on any other machine when you try to compile the
To compile the release version of the code run:
This will compile your code with some optimizations enabled. If you use a debugger on the ‘release’ build, it will not be able to show you the original source code, or line numbers, most of the time. Optimizations sometimes expose some bugs in your code that would not show up when no optimizations are enabled, but since optimizations tend to reorder your code while compiling, an optimized version of your code is not optimal for debugging.
To compile your code in debug mode, run
make debug instead of
If you compile in release mode, you will an executable called
shell. If you
compile in debug mode, you will get an executable call