Inspiration
I wanted to stop trusting the "magic" of the terminal and understand the machinery. For the Build From Scratch hackathon, I challenged myself to build a POSIX-compliant shell without high-level shortcuts like system(). My goal was to use the raw system calls that power the OS.
What it does
CppShell is a fully functional command-line interpreter that replicates core shell behaviors:
- REPL Cycle: Processes user input in real-time.
- Infinite Pipelines: Chains commands (e.g.,
cmd1 | cmd2 | cmd3) via kernel pipes. - I/O Redirection: Supports output redirection (
>) and append mode (>>). - Persistent History: Saves and loads session history automatically.
- Advanced Parsing: Handles single quotes, double quotes, and backslash escapes correctly.
How we built it
Built in C++ on Linux using three main architectural pillars:
- The Parser: A custom state-machine tokenizer that handles complex quoting and escape sequences character-by-character.
- Process Management: Uses
fork()to clone the shell andexecvp()to perform a "brain transplant," replacing the process memory with the target program. - Pipeline Logic: A "bucket brigade" loop that creates
pipe()channels and usesdup2()to surgically rewireSTDOUTandSTDINbetween independent processes.
Challenges we ran into
- Zombie Processes: Commands would finish but remain in the process table. I had to implement careful
waitpidloops to reap them. - Deadlocks: In multi-stage pipelines, forgetting to close a single write-end caused the reader to hang forever.
- Parsing: Distinguishing between literal strings inside
'single quotes'vs escapable strings inside"double quotes"required multiple rewrites.
Accomplishments that we're proud of
- Zero High-Level Dependencies: Built entirely with raw POSIX syscalls (
unistd.h,sys/wait.h,fcntl.h). - Robust Pipelines: Can handle arbitrarily long command chains.
- Usability: With persistent history and auto-complete, it feels like a real tool.
What we learned
- Files are Integers: I gained a deep appreciation for how Linux treats File Descriptors.
- Cost of Forking: Learned how expensive yet powerful cloning a process state is.
- Complexity of Text: Interpreting a simple string correctly is harder than it looks.
What's next for CppShell
- Signal Handling: Implementing
Ctrl+Chandling. - Environment Variables: Adding
exportand variable expansion ($VAR). - Scripting: Adding support for
.shscript execution.
Log in or sign up for Devpost to join the conversation.