This repository contains an enhanced C++ implementation of a small interactive shell (REPL). It started from the CodeCrafters "Build Your Own Shell" challenge and was extended with command history, tab completion, pipelines, redirections, cross-platform process spawning and several developer-friendly helpers.
- Cross-platform process spawning: POSIX
fork+execvand WindowsCreateProcessWimplementations. - Pipeline support (
|), including proper pipe wiring on POSIX and Windows. - Redirections:
>,>>and numeric fd redirections (e.g.2>err.txt). - Builtin commands:
echo,cd(supports~),pwd,type,exit,history(with-c,-d,-r,-w,-asubcommands). - Command history: in-memory list plus optional file persistence controlled by
the
HISTFILEenvironment variable. - Tab completion for commands (uses a cached set of executables + builtins).
- Robust argument parsing including single/double quotes and backslash escapes; throws on unclosed quotes.
- Terminal raw-mode input and arrow-key navigation for history (POSIX via
termios, Windows via_getch). - Scoped redirections for builtins so builtins honor redirection during their execution.
src/main.cpp— program entrypoint.src/shell.h,src/shell.cpp— main shell class, parsing, dispatching, builtins, pipeline execution, completion and history.src/utils.h— helpers:getenv_safe,get_home_directory,run_program_and_wait,parse_args, andScopedRedir.src/inputHelper.h— small cross-platform helper for raw-mode input andget_char_raw()abstraction used by the REPL.CMakeLists.txt— build configuration.
- Input: user-entered command lines (strings) via a REPL prompt.
- Output: stdout/stderr of builtins and spawned processes; exit status comes from executed programs (pipelines are executed and waited upon).
- Error modes: parsing errors (e.g. unclosed quotes) raise runtime errors printed to stderr; spawn errors return messages to stderr.
Edge cases considered: empty lines, unclosed quotes, missing redirection targets, trying to run non-executable files, and PATH entries with permission errors (these are skipped during executable cache population).
Requirements: C++20 compiler, CMake (3.10+ recommended).
Windows (Developer Command Prompt / PowerShell):
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
# Executable typically: build\Release\shell.exeWSL / Linux / macOS:
cmake -S . -B cmake-build-debug-wsl -DCMAKE_BUILD_TYPE=Release
cmake --build cmake-build-debug-wsl -- -j$(nproc)
# Executable typically: cmake-build-debug-wsl/shellThere is a helper script your_program.sh that can be adapted to run the
built binary in your environment.
Start the shell and try commands:
./cmake-build-debug-wsl/shell
# or on Windows
build\Release\shell.exeExamples inside the prompt:
-
Simple builtins:
- echo:
echo hello world - pwd:
pwd - cd:
cd /tmporcd ~ - type:
type lsortype echo - exit:
exitorexit 2
- echo:
-
History:
- up/down arrows to navigate previous commands (raw-mode input)
HISTFILEenv var controls persisted history file path; history is read at startup and appended on exit (if configured).historybuiltin examples:history,history 10,history -c,history -d 5,history -w historyfile,history -r historyfile,history -a historyfile.
-
External programs and completion:
- tab completion for commands (builtins + cached executables from
PATH). type <name>reports whether a name is a builtin or prints the resolved path to an executable.
- tab completion for commands (builtins + cached executables from
-
Pipelines and redirections:
ls -la | grep txt | wc -lecho hi > out.txtecho again >> out.txtls 2> err.txtmyprog 1>out.txt 2>>err.txt
Notes:
- Numeric fd redirections are supported (e.g.
2>filetargets stderr). - Builtins use
ScopedRedirso redirection affects builtin output as expected.
- Argument parsing:
parse_argsinsrc/utils.h. - Line parsing into pipeline + redirections:
parse_line_to_pipelineinsrc/shell.cpp. - Pipeline execution:
execute_pipelineinsrc/shell.cpp(separate implementations for POSIX and Windows). - Single-command execution:
execute_simple_commandandrun_program_and_wait(src/utils.h). - History and completion:
populate_executable_cache,read_history,write_history,handle_completioninsrc/shell.cpp. - Terminal input:
enableRawMode,disableRawMode, andget_char_rawinsrc/inputHelper.h.
- No job control (background
&,fg,bg) yet. - Environment variable and tilde expansion is limited (tilde
~support incdonly). No$VARexpansion or globbing implemented. - Quoting and escaping aims to be shell-like but is not a full POSIX shell parser; edge cases may differ from bash/zsh.
Planned/possible next steps (I can implement any of these on request):
- Add
$VARexpansion and filename globbing. - Implement job control and background/foreground management.
- Add unit tests for
parse_args,parse_line_to_pipelineandexecute_pipelinebehavior.
This project was started from the CodeCrafters Shell challenge. Respect the original challenge terms when sharing or publishing derived work.