The C programming language was used to develop a Linux shell. This project was a programming assignment for the CPS1012: Operating Systems and Systems Programming 1 course, a course forming part of my B.Sc. in Computer Science.
Eggshell is a command-line interpreter for the Linux OS. It was designed to cater for the following:
- Shell Variables
- Internal and External Commands
- Input and Output Redirection
- Piping
- Process Management
These will be explained in the sub-sections to follow.
Shell variables are character strings to which a value is assigned. Shell variable names should be in UPPERCASE and can contain any of the following:
- letters ( A-Z )
- numbers ( 0-9 )
- underscores ( _ )
Eggshell was designed to cater for these shell variables by default:
PATH
- The search path used to launch external commands
PROMPT
- The string presented to the user to show that the shell is ready to accept command input
CWD
- The path of the current working directory to which all file operations are relative to
USER
- The current user's username
HOME
- The current user's home directory
SHELL
- The current user's shell
TERMINAL
- The name of the terminal executing the current Eggshell session
EXITCODE
- The exit code returned by the last program run by the shell
An assignment statement is used to modify existing shell variables or create new ones.
A shell variable's value is obtained by prefixing its name with a $. If a valid name is detected, the shell obtains its value from the list of shell variables.
> NEW_VAR=#
> print $NEW_VAR
#
> PROMPT=$NEW_VAR
# print The prompt has been changed to: $PROMPT
The prompt has been changed to: #
Eggshell's command-line interpreter recognises a number of internal (built-in) and external commands.
When a new command is entered, it is compared to a list of built-in commands. If a command is not recognised as such, the shell treats the input as a call to an external command.
Eggshell was designed to cater for the following internal commands:
exit
- Terminates all running processes spawned by the Eggshell instance and quits the program
print
- Echoes text expressions or variable values to standard output
chdir
- Changes the current working directory (CWD)
all
- Prints all the shell variables in key-value pairs
source
- Provides scripting functionality. This command takes the name of a script file as its only argument and proceeds to open this file and execute all of its commands. Each executed command behaves exactly in the same way as if it were typed in
Eggshell's current implementation traps and handles errors when commands fail. It returns appropriate error messages indicating the reason for failure.
The shell considers commands not included in the list above as external commands. It searches for matching program binaries through the system search path (PATH) and launches them as separate processes by forking.
Eggshell supports the following redirection operators:
>
- Redirects a command's output into a file
>>
- Redirects a command's output into a file, appending to the file's existing contents
<
- Uses a file's contents as input to a command
<<<
- Uses text as here string input to a command
The usage of these commands is shown in the examples below, where 'cmd' denotes an arbitrary command (internal/external) with zero or more arguments and 'f.txt' refers to an arbitrary file.
# cmd > f.txt
# cmd >> f.txt
# cmd < f.txt
# cmd <<< 'text
more text
even more text'
The Unix piping operator '|' was implemented to chain multiple processes by their input and output streams. This allows the output (stdout) of one process to feed directly into the input (stdin) of the next, and so forth.
As an example, consider the 4 command sequence below:
cat m.txt | grep a | wc -l | figlet > finish.txt
The output of one command is passed as input to the next, as if the commands are connected together as one whole process. The diagram below helps to visualise this concept.
The piping process for 4 commands
Shells reserve a keyboard shortcut (typically CTRL
+ C
) to interrupt running processes. Given that Eggshell is a process itself, this shortcut would also terminate the current Eggshell instance.
To prevent this, the SIG INT signal triggered with this shortcut is trapped and forwarded to any process spawned by Eggshell, forcing this process only to exit, and not Eggshell itself.
A detailed description of this project's deliverables can be found here.
A detailed technical documentation of the source code written can be found here.