The Minishell project at 42 challenges students to build a basic Unix shell from scratch using the C programming language. This shell must replicate the behavior of Bash for a subset of its features, including parsing, environment management, redirections, and piping — all while handling user input interactively and robustly.
The project emphasizes process management, signal handling, lexing and parsing, and advanced data structures, such as an Abstract Syntax Tree (AST).
The goal of Minishell is to create a functional shell with behavior that closely resembles /bin/bash in terms of supported features. The shell should support:
- Tokenization and Parsing using an Abstract Syntax Tree (AST)
- Execution of commands with redirections and pipes
- Signal handling (e.g.,
Ctrl+C,Ctrl+\) - Environment variable management (
export,unset, etc.) - Built-in commands
Each shell cycle follows:
read → parse → execute → wait → repeat
Your shell must:
- Display a prompt and wait for user input
- Implement lexer to tokenize input and parser to build the AST
- Execute commands from the AST with correct handling of:
- Redirections:
>,>>,<,<< - Pipes:
|
- Redirections:
- Implement the following built-in commands:
echo,cd,pwd,export,unset,env,exit
- Properly manage environment variables (
envp) - Handle errors gracefully (e.g., invalid syntax, command not found)
- Exit cleanly on
Ctrl+Dand respond toCtrl+Cappropriately
- Input is read using
readline() - Tokenization respects quotes (
',") and escape characters - Parsing is done recursively via a binary tree-based AST
- The tree organizes operators (pipes/redirections) and command nodes
The parser builds an AST where:
- Each node represents a command, redirection, pipe, or logical operator.
- Left/right children represent left/right sides of compound commands.
This design enables:
- Recursive command execution.
- Natural support for parentheses and complex shell logic.
Example:
echo hello | grep h && ls > out.txtYields an AST like:
&&
/ \
| >
/ \ / \
echo grep ls out.txt
Execution follows post-order traversal of this tree structure.
- Commands are executed via
fork()andexecve() - Built-ins are executed in the parent process (except in pipelines)
- Pipes and redirections are managed using
dup2(),open()andclose() - Exit codes are tracked and used for conditionals (like
&&,||in bonus)
SIGINT(Ctrl+C): should interrupt and display a new promptSIGQUIT(Ctrl+\): should be ignoredSIGTERMandEOFare handled gracefully
>: redirect output to a file (overwrites the file if it already exists)>>: append output to a file<: read input from a file<<: here-document (read input in real-time until it finds the given delimiter)
For the minishell_bonus version:
- Support for
&&and||conditional execution - Handle parentheses for grouped commands:
(cmd1 && cmd2) || cmd3 - Wildcards (
*) viaglobbing
make./minishellYou'll see a custom prompt (e.g., minishell$) awaiting input.
minishell$ export PATH=$PATH:/usr/bin
minishell$ echo "Hello World"
minishell$ ls -l | grep minishell >> logs.txt
minishell$ cat logs.txt
minishell$ exitTo clean compiled objects:
make cleanTo clean everything including the binary:
make fcleanTo recompile from scratch:
make re-
$\color{Crimson}{\textbf{Improper quoting}}$ → Ensure correct token handling inside quotes -
$\color{Crimson}{\textbf{Unclosed pipes or redirs}}$ → Syntax errors must be handled -
$\color{Crimson}{\textbf{Zombie processes}}$ → Alwayswait()for children -
$\color{Crimson}{\textbf{Memory leaks}}$ → Free all memory after each command cycle -
$\color{Crimson}{\textbf{Bad fork logic}}$ → Don't fork built-ins unless necessary -
$\color{Crimson}{\textbf{Unprotected global state}}$ → Use signal-safe logic
- Deepened understanding of Unix process lifecycle, including
fork,exec, andwait - Learned how to implement signal-safe input handling
- Built a recursive parser with AST, applying compiler theory principles
- Managed complex memory and file descriptor lifecycles in C
- Strengthened debugging and error-handling strategies
The Minishell project is a deep dive into systems programming, shell architecture, and process management. It gives real-world experience in writing a command interpreter, handling low-level operations, and structuring a program using an AST, making it a valuable step toward becoming a proficient systems developer.