A fully-featured, POSIX-compliant shell written in Rust, built as part of the "Build Your Own Shell" Challenge.
- Command Execution: Execute external programs with full argument support
- Builtin Commands: Native implementations of
echo,exit,type,pwd,cd, andhistory - Pipeline Support: Chain commands using
|operator - I/O Redirection: Full support for
>,>>,2>,2>>, and1>operators - Command History: Persistent command history with read/write/append operations
- Tab Completion: Intelligent autocomplete for commands in PATH
- Quote Handling: Proper parsing of single quotes (
'), double quotes ("), and escape sequences - Trie-based Autocomplete: Fast command suggestions using prefix tree data structure
- Flexible I/O: Support for stdin/stdout/stderr redirection and piping
- PATH Resolution: Automatic executable discovery across PATH directories
The codebase is organized into focused modules:
src/
โโโ main.rs # Entry point and REPL loop
โโโ shell.rs # Shell state and execution orchestration
โโโ command.rs # Command parsing and structure
โโโ builtins.rs # Builtin command implementations
โโโ shell_io.rs # I/O abstraction layer (stdin/stdout/stderr/pipes/files)
โโโ trie.rs # Trie data structure for autocomplete
โโโ autocomplete.rs # Rustyline integration for tab completion
Manages shell state including:
- Current working directory
- PATH environment variable
- Command history
- Exit status codes
- Pipeline execution coordination
Handles command parsing with support for:
- Quote escaping (single, double, and backslash)
- Argument tokenization
- Output redirection operators
- Pipeline splitting
Implements builtin commands:
exit <code>- Exit shell with status codeecho <args>- Print arguments to stdouttype <cmd>- Display command type (builtin or path)pwd- Print working directorycd <path>- Change directory (supports~for home)history [n]- Show command historyhistory -r <file>- Read history from filehistory -w <file>- Write history to filehistory -a <file>- Append new history to file
Provides unified I/O abstraction for:
- Standard streams (stdin/stdout/stderr)
- File descriptors
- Pipes (for pipeline chaining)
- Conversion to
std::process::Stdio
Efficient prefix tree implementation for:
- Fast command lookup
- Fuzzy matching
- Autocomplete suggestions
Integrates with rustyline for:
- Tab completion
- Command suggestions
- Visual feedback (bell on no matches)
- Rust 1.80+ (specified in
Cargo.toml) - Cargo package manager
# Clone the repository
git clone <your-repo-url>
cd shell-rust
# Build the project
cargo build --release
# Run the shell
./your_program.sh# Basic command execution
$ echo Hello, World!
Hello, World!
# Pipeline chaining
$ cat file.txt | grep pattern | wc -l
# Output redirection
$ echo "log entry" >> output.log
$ command 2> errors.log
# Tab completion
$ ec<TAB>
echo # autocompletes
# Command history
$ history 5
1 echo test
2 pwd
3 cd ~
4 ls -la
5 history 5
# Change directory
$ cd ~/projects
$ pwd
/Users/username/projectsThe command parser correctly handles:
- Single quotes: Preserves literal values (except
\') - Double quotes: Allows variable expansion and escapes
\``,$,", ````, and\n - Backslash escaping: General escape character outside quotes
Pipelines are executed by:
- Splitting commands on
|delimiter - Creating pipe pairs between consecutive commands
- Redirecting stdout โ pipe writer โ stdin
- Waiting for all processes in pipeline chain
Supports multiple redirection operators:
>/1>- Redirect stdout (truncate)>>/1>>- Redirect stdout (append)2>- Redirect stderr (truncate)2>>- Redirect stderr (append)
Uses a Trie for O(k) prefix matching where k is the prefix length:
- Scans PATH directories at startup
- Builds trie of all executable names
- Provides instant suggestions on tab press
| Command | Description | Example |
|---|---|---|
exit <code> |
Exit shell with status | exit 0 |
echo <args> |
Print arguments | echo "Hello World" |
type <cmd> |
Show command type | type ls |
pwd |
Print working directory | pwd |
cd <path> |
Change directory | cd /tmp |
history [n] |
Show history | history 10 |
history -r <file>- Read history from filehistory -w <file>- Write complete history to filehistory -a <file>- Append new entries to file
# Run tests
cargo test
# Run with debug output
debug: true # in codecrafters.yml- rustyline (17.0.2) - Readline implementation with history and completion
- regex (1.12.2) - Command parsing and pattern matching
- is_executable (1.0.5) - Portable executable detection
- Enum-based I/O:
InputandOutputenums provide type-safe I/O handling - Trie for Autocomplete: O(k) prefix matching outperforms linear search
- Separate Parsing: Command parsing is isolated from execution logic
- Child Process Management:
ChildOrStatusenum handles both async and sync command execution - Persistent History: History stored in
HISTFILEenvironment variable location
- Environment variable expansion (
$VAR) - Command substitution (
`cmd`or$(cmd)) - Background jobs (
&) - Job control (
fg,bg,jobs) - Glob expansion (
*.txt) - Signal handling (Ctrl+C, Ctrl+Z)
- Alias support
This project is part of the CodeCrafters challenge.
Built as part of the CodeCrafters Shell challenge.