https://github.com/chungquantin/baby-shell
Baby shell implementation in C supports most OS commands with pipelining and sequencing
https://github.com/chungquantin/baby-shell
c libc os shell
Last synced: about 1 year ago
JSON representation
Baby shell implementation in C supports most OS commands with pipelining and sequencing
- Host: GitHub
- URL: https://github.com/chungquantin/baby-shell
- Owner: chungquantin
- Created: 2023-03-06T13:49:24.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2023-09-15T08:35:34.000Z (almost 3 years ago)
- Last Synced: 2025-04-01T17:18:21.170Z (about 1 year ago)
- Topics: c, libc, os, shell
- Language: C
- Homepage:
- Size: 15.6 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# 👶 Baby Shell

## Description
Reimplement the OS Shell in C using libc API. This shell covers most of the features of a shell.
## How does shell works?
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.
### Tokenizer
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"`
### Command execution
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.
#### Forking process
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
pid_t
fork(void);
DESCRIPTION
fork() causes the creation of a new process...
```
Read from `man fork`
### Pipe
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`
## Features
- [x] Execute single command
- [x] Sequencing and execute multiple commands (Token: `;`)
- [x] Input / Output redirection (Token: `>`, `<`)
- [x] Pipelining command (Token: `|`)
- [x] Executing scripts (Token: `source`)
- [ ] Auto code completion
- [ ] SSH remote connection
- [ ] Custom config file similar to `.zshrc` or `.bashrc`
## Development Guideline
The [Makefile](Makefile) contains the following targets:
- `make all` - compile everything
- `make tokenize` - compile the tokenizer demo
- `make tokenize-tests` - compile the tokenizer demo
- `make shell` - compile the shell
- `make shell-tests` - run a few tests against the shell
- `make test` - compile and run all the tests
- `make clean` - perform a minimal clean-up of the source tree
The [examples](examples/) directory contains an example tokenizer. It might help.
## Contributions
Created by **Micheal Baraty** and **Tin Chung**