Reimplement the OS Shell in C using libc API. This shell covers most of the features of a shell.
Shell is simply an interface layer that uses libc
API to operate a specific command. Terminal and shell is a two different concepts. Terminal is an application that uses a shell as a backend for the user to communicate with the kernel.
First stage of a shell is to tokenize the command into tokens that will be processed in a later stage for command execution. You can consider a tokenizer is a preprocessing stage before moving it to the main cook. There is a rule for tokenizing:
- Special tokens:
,
,;
,|
- String:
"Hello world"
To understand how a shell executes commands, you must have a fundamental knowledge of the process in the operating system. Whenever a process uses a system call like execve
or execvp
to execute the binary command, the process exits with the success code exit(0)
or error code exit(1)
. Hence, a single process shell is unable to run interactively while waiting for user input.
The solution is simple, for every command, we will fork another process which copies the memory of that process to the another. In this way, the context of the old process is the same while the main program is no longer interrupted after the execution.
NAME
fork -- create a new process
SYNOPSIS
#include <unistd.h>
pid_t
fork(void);
DESCRIPTION
fork() causes the creation of a new process...
Read from man fork
The pipelining command is a special thing in every shell, it makes use of OS file descriptors to stream the output from stdout
to a file descriptor or to read the input from file descriptor instead of stdin
. Implementing a pipe requires an API called pipe()
.
NAME
pipe - Postfix delivery to external command
SYNOPSIS
pipe [generic Postfix daemon options] command_attributes...
DESCRIPTION
The pipe(8) daemon processes requests from the Postfix queue ma
nager to...
Read from man pipe
- Execute single command
- Sequencing and execute multiple commands (Token:
;
) - Input / Output redirection (Token:
>
,<
) - Pipelining command (Token:
|
) - Executing scripts (Token:
source
) - Auto code completion
- SSH remote connection
- Custom config file similar to
.zshrc
or.bashrc
The Makefile contains the following targets:
make all
- compile everythingmake tokenize
- compile the tokenizer demomake tokenize-tests
- compile the tokenizer demomake shell
- compile the shellmake shell-tests
- run a few tests against the shellmake test
- compile and run all the testsmake clean
- perform a minimal clean-up of the source tree
The examples directory contains an example tokenizer. It might help.
Created by Micheal Baraty and Tin Chung