A small interactive shell for Linux, written in C++17. It provides a command prompt, a set of built-in commands, external command execution (foreground and background), I/O redirection, pipelines, job signals, and a persistent command history.
make # optimised build -> ./a.out
make debug # -O0 -g with AddressSanitizer + UBSan
make run # build and start the shell
make clean # remove objects and the binaryRequirements: g++ with C++17 support and a Linux system (the pinfo command
reads /proc, so it is Linux-only).
The build is incremental — each .cpp compiles to its own .o, so editing one
file recompiles only that file. Override the toolchain or flags from the command
line if needed, e.g. make CXX=clang++ or make CXXFLAGS="-O3 -march=native".
./a.outThe prompt has the form:
<user>@<host>:~<path>>
where <path> is the working directory shown relative to the directory the
shell was started in (that directory itself is shown as ~). Directories
outside it are shown by their absolute path.
Type exit (or press Ctrl-D) to leave the shell.
Redrawn before every command. Shows the effective user, the hostname, and the working directory relative to the shell's launch directory.
| Command | Behaviour |
|---|---|
cd [dir] |
Change directory. Supports no argument and ~ (launch dir), - (previous dir, prints the new path), ., .., ~/sub, and absolute/relative paths. Reports the reason on failure. |
pwd |
Print the absolute working directory. |
echo [args...] |
Print the arguments separated by single spaces. Single and double quotes group text and are removed. |
ls [-a] [-l] [path...] |
List directory contents (or a single file). -a includes dotfiles, -l shows the long format. Flags may be combined (-al). Entries are sorted. Multiple paths get a path: header. |
pinfo [pid] |
Show pid, state, virtual memory, and executable path for a process (defaults to the shell). Reads /proc. |
search <name> |
Recursively look for a file or directory of that name under the current directory. Prints True or False. |
history [n] |
Show the last n commands (0–20, default 10). History is de-duplicated for consecutive repeats and capped at 20 entries. |
exit |
Terminate the shell. |
Anything that is not a built-in is run via fork + execvp.
- Foreground: the shell waits for the process and stays responsive to
Ctrl-C/Ctrl-Z, which are forwarded to the child. - Background: append
&. The shell prints[bg] <pid>and continues. The job runs in its own process group so it does not steal the terminal, and its completion (<pid> done) is reported before the next prompt.
<, >, and >> are supported and may be combined:
cat < input.txt
ls -l > listing.txt
echo more >> listing.txt
sort < data.txt > sorted.txtOutput files are created with mode 0644 (> truncates, >> appends). A
missing input file or a missing filename after an operator is reported and the
command is skipped.
Any number of stages separated by |:
cat file.txt | head -20 | tail -5 | wc -lAll stages run concurrently, connected by pipes; the shell waits for every stage. Redirection may be used inside a pipeline stage.
Separate commands on one line with ;:
cd src ; ls -l ; pwdCtrl-C(SIGINT) — interrupts the foreground job, not the shell.Ctrl-Z(SIGTSTP) — stops the foreground job and returns to the prompt.Ctrl-D(EOF) — logs out.
Commands are stored in history.txt in the shell's launch directory. The file
is kept trimmed to the last 20 entries and is reloaded on the next startup.
| File | Responsibility |
|---|---|
main.cpp |
Startup, signal setup, the read–eval loop. |
headers.h |
Shared includes and function declarations. |
prompt.cpp |
Prompt rendering. |
tokenize.cpp |
Splitting input by whitespace, ;, ` |
executor.cpp |
Dispatch: ; splitting, pipeline/redirection/built-in routing, signal handlers. |
cd.cpp, pwd.cpp, echo.cpp, ls.cpp |
Built-ins. |
background.cpp |
fork/exec for external commands, background job tracking and reaping. |
redirection.cpp |
< / > / >> handling. |
pipe.cpp |
Pipeline setup and execution. |
pinfo.cpp |
/proc inspection. |
search.cpp |
Recursive file search. |
history.cpp |
History ring buffer and file persistence. |
reference.cpp |
Earlier standalone reference implementation. Not part of the build. |
pinforequires/procand therefore Linux.- Built-ins (
cd,history, …) inside a pipeline run in a child process, socdin a pipeline does not affect the shell — this matches standard shells. - Environment-variable expansion (
$VAR), globbing (*), and command substitution are not implemented.