A simple bash-like shell we built from scratch. The idea was to understand how commands actually run under the hood—lexing, parsing, expanding variables, and execution of the actual command.
MXCALLL Lexer, Parser & Expansion |
moniross Execution & Signals |
Input: echo "Hello $USER" | grep $USER > output.txt
↓
[Lexer] → tokens: ["echo", "Hello $USER", "|", "grep", "$USER", ">", "output.txt"]
↓
[Parser] → commands: [{cmd: echo, args: [...]}, {cmd: grep, args: [...], output: output.txt}]
↓
[Expander] → resolve variables, remove quotes
↓
[Executor] → fork, pipe, redirect, execute, wait
When you type a command and hit enter, here's what happens:
-
Reading input – We use
readline()to grab what you typed and add it to history. -
Tokenizing – The lexer breaks your input into tokens (words, operators like
|,>,<, etc.). Think of it like splitting a sentence into individual words and punctuation marks. -
Parsing – The parser looks at those tokens and builds command structures. It figures out what's a command, what's an argument, where redirections go, and how pipes connect things.
-
Expanding – Before running anything, we handle stuff like
$USERor$?and strip away quotes that bash would remove. -
Executing – This is where things get real:
- We open heredocs if needed
- Set up pipes between commands
- Fork child processes for external commands
- Run builtins directly without forking
- Wait for everything to finish and collect exit codes
-
Cleanup – Close file descriptors, free memory, and get ready for the next command.
The whole loop lives in src/main.c, and each stage has its own folder under src/ (1-Lexer, 2-Parser, 3-Expander, 4-Executer).
Minishell/
├── src/
│ ├── main.c # Main loop and signal setup
│ ├── 1-Lexer/ # Tokenization
│ ├── 2-Parser/ # Building command structures
│ ├── 3-Expander/ # Variable expansion & quotes
│ ├── 4-Executer/ # Process execution
│ └── builtins/ # Built-in commands (cd, echo, etc.)
├── includes/
│ └── minishell.h # Shared headers and structs
└── libft/ # Helper functions
Features of Our Minishell
- Prompt with history
- Quotes handling (
'and") - Redirections (
<,>,<<,>>) - Pipes (
|) - Environment variables (
$VAR,$?) - Signals (ctrl-C, ctrl-D, ctrl-)
- Builtins:
echo -n,cd,pwd,export,unset,env,exit
Things That Are Not Supported
- Logical operators (
&&,||) with parenthesis - Wildcards (
*)