A Unix shell implementation built in C as part of the 42 curriculum. The project focuses on understanding how a real shell works internally by implementing parsing, process management, environment handling, pipes, redirections, signals, and built-in commands from scratch.
Goal: Build a modular, maintainable, and fault-tolerant shell inspired by Bash while following software engineering best practices.
- Interactive shell using
readline - Command history
- PATH resolution
- Environment variable management
- Variable expansion (
$VAR,$?) - Single and double quote handling
- Pipelines (
|) - Input/Output redirections
<>>><<(heredoc)
- Built-in commands
echocdpwdexportunsetenvexit
- Signal handling
Ctrl+CCtrl+DCtrl+\
- Process creation using
fork()andexecve()
User Input
│
readline()
│
┌───────▼────────┐
│ Tokenizer │
└───────┬────────┘
│ Tokens
┌───────▼────────┐
│ Parser │
└───────┬────────┘
│ AST / Command List
┌───────▼────────┐
│ Executor │
└───────┬────────┘
┌───────────┴───────────┐
│ │
Builtins External Commands
│ │
└───────────┬───────────┘
│
Update Exit Status
│
Next Prompt
src/
│
├── shell/
│ └── main.c
│
├── env/
│ ├── env_init.c
│ ├── env_get.c
│ ├── env_set.c
│ ├── env_unset.c
│ └── env_to_array.c
│
├── lexer/
│
├── parser/
│
├── executor/
│
├── builtin/
│
├── signals/
│
└── utils/
This project is intentionally designed using modern software engineering practices despite being written in C.
-
Single Responsibility
- Each module has one responsibility.
- Environment manager only manages environment.
- Parser only parses.
- Executor only executes.
-
Open / Closed
- New builtins can be added without modifying executor logic.
-
Liskov Substitution
- Uniform interfaces for commands and builtins.
-
Interface Segregation
- Modules expose only the APIs they need.
-
Dependency Inversion
- Modules communicate through interfaces rather than global state.
This project explores real operating system concepts including:
- Unix Process Model
- Process Creation (
fork) - Program Execution (
execve) - Parent / Child synchronization
- Exit status propagation
- Signal handling
- Pipes and IPC
- File descriptors
- I/O redirection
- Environment management
- PATH resolution
- Memory ownership
- Resource lifetime
- Error propagation
- Modular architecture
- Low coupling
- High cohesion
- Clear ownership of resources
- Minimal global state
- Deterministic cleanup
- Defensive programming
- Fail-fast error handling
- Valgrind clean
- C99
- POSIX
- GNU Readline
- Make
- GCC
- Valgrind
- GDB
- ✅ Shell skeleton
- 🚧 Environment manager
- ⏳ Tokenizer
- ⏳ Variable expansion
- ⏳ Parser
- ⏳ Builtins
- ⏳ Executor
- ⏳ Redirections
- ⏳ Pipelines
- ⏳ Heredoc
- ⏳ Signals
- ⏳ Error handling
- ⏳ Memory optimization
Through this project, the following concepts are explored in depth:
- Unix Internals
- Shell Architecture
- Compiler-style Lexing & Parsing
- Process Lifecycle
- Inter-Process Communication (IPC)
- File Descriptor Management
- Memory Management in C
- Systems Programming
- Software Architecture
- Fault-Tolerant Design
- Defensive Programming
- Modular API Design
make
./minishellRather than simply satisfying the project requirements, this implementation aims to serve as a production-quality educational codebase demonstrating clean architecture, maintainability, and systems programming best practices.