CodeCrafter's "Build Your Own Shell" Challenge.
A custom, POSIX-compliant shell implementation written in Go. This project demonstrates low-level terminal control, command parsing, pipeline management, and built-in command handling.
The project is organized into a modular structure separating the REPL logic, command parsing, execution, and terminal management.
.
├── main.go # Entry point: REPL loop, pipeline orchestration, and raw mode setup
└── pkg/
├── commands/
│ └── registry.go # Command registry, built-in definitions, and Trie-based autocomplete
├── history/
│ └── history.go # Command history management (in-memory & file persistence)
├── parser/
│ └── parser.go # Input tokenizer handling quotes (' " \), spaces, and pipes
├── term/
│ └── term.go # Low-level terminal control (Raw mode vs Canonical mode)
└── executor/
└── redirect.go # Utilities for handling standard I/O redirection
The heart of the shell. It manages the lifecycle of the application:
- REPL Loop: Reads input byte-by-byte to handle special keys (Tab, Arrow keys) in real-time.
- Pipeline Orchestration: Parses commands separated by
|, createsos.Pipeconnections between them, and managessync.WaitGroupfor concurrent execution. - Signal Handling: Detects special keys like
Ctrl+Cor<Arrow Keys>for history navigation.
registry.go: Maintains a map of built-in commands (cd,exit,type,echo,pwd,history).- Trie Implementation: Uses a prefix tree (Trie) to index all executables in the system
$PATHand built-ins. This powers the Tab Autocomplete feature.
parser.go: specialized tokenizer that converts raw input strings into executable tokens.- Quote Handling: Correctly handles single quotes
', double quotes", and backslash escapes\, ensuring arguments with spaces are grouped correctly (e.g.,"echo 'hello world'"becomes["echo", "hello world"]).
term.go: Usessyscallto switch the terminal from Canonical Mode (buffered input) to Raw Mode.- Why? This is required to capture keystrokes like
Tab(for autocomplete) andUp/Down Arrows(for history) immediately, without waiting for the user to press Enter.
history.go: Manages a thread-safe list of previous commands.- Persistence: Reads from and writes to the file defined in
HISTFILE(similar to.bash_history). - Navigation: Provides methods
GetUpEntry()andGetDownEntry()for scrolling through commands.
- Redirect Logic (in
main.go&pkg/executor): Handles standard file descriptors manipulation for: >(Overwrite stdout)>>(Append stdout)2>(Overwrite stderr)2>>(Append stderr)
- Pipeline Support: Run commands in parallel like
ls | grep .go | sort. - I/O Redirection: Support for
stdoutandstderrredirection (e.g.,ls > file.txt 2> error.log). - Tab Autocomplete: Intelligently suggests commands based on
$PATHand built-ins. - Command History: Persistent history with Arrow key navigation.
- Built-ins:
cd: Change directory (supports~).type: Reveal if a command is a built-in or executable path.history: View or manipulate session history.echo: Print arguments to stdout.
To build and run the shell:
# Build the binary
go build -o myshell main.go
# Run the shell
./myshell