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:

  1. The Parser: A custom state-machine tokenizer that handles complex quoting and escape sequences character-by-character.
  2. Process Management: Uses fork() to clone the shell and execvp() to perform a "brain transplant," replacing the process memory with the target program.
  3. Pipeline Logic: A "bucket brigade" loop that creates pipe() channels and uses dup2() to surgically rewire STDOUT and STDIN between independent processes.

Challenges we ran into

  • Zombie Processes: Commands would finish but remain in the process table. I had to implement careful waitpid loops 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+C handling.
  • Environment Variables: Adding export and variable expansion ($VAR).
  • Scripting: Adding support for .sh script execution.

Built With

Share this project:

Updates