A Unix-like command interpreter written from scratch in C: no parser generator, no readline,
nothing beyond libc and ncurses. It folds shell operators into a binary execution tree, then
walks that tree with fork, pipe, dup2 and execve.
Historical project, written in 2018 during the Epitech curriculum and preserved as it was. Documentation rewritten in 2026.
input → line editing → tokenisation → operator tree → fd wiring → fork/execve → status
Parsing is not a lexer/parser/AST pipeline. Each node holds the raw text it still has to
resolve; the builder scans for the first operator type present, in a fixed precedence order
((, ;, |, <<, <, >>, >, ||, &&), splits the string at its first occurrence,
and recurses on both halves. Leaves are commands. So ls -l | grep .c > out.txt becomes:
flowchart TD
P["pipe"] --> L["ls -l"]
P --> R["redirect"]
R --> RL["grep .c"]
R --> RR["out.txt"]
control_pipe forks and crosses a pipe, then evaluates its right subtree — which is itself an
operator, so control_right_chevron runs next and inherits that stdin. Operators compose
because every handler asks whether its child is another operator and re-enters the dispatcher
if so. Each one saves the descriptor it is about to overwrite and restores it afterwards, so a
pipeline does not poison the next command in a sequence.
The interactive prompt clears ICANON and ECHO, so the shell sees raw bytes and redraws the
line itself through termcap — arrow keys, Ctrl-L, Ctrl-U and history navigation are all handled
by hand.
| Directory | Responsibility |
|---|---|
sources/line_editing/ |
Raw terminal mode, keystrokes, history navigation |
sources/parser_ll/ |
Operator-tree construction and dispatch |
sources/operator/ |
One handler per operator — where forks and descriptors live |
sources/execution/ |
PATH lookup, execve, termination diagnostics |
sources/built_in/ |
Built-ins, running in-process so they can mutate shell state |
sources/backticks/ |
Command substitution, by re-entering the evaluator |
lib/my/ |
In-house libc subset: my_printf, get_next_line, string helpers |
Operators — ; | < << > >> && || and ( ) grouping, evaluated recursively.
Execution — PATH lookup, exit-status propagation, and tcsh-style diagnostics for ~40
termination signals (Segmentation fault, Killed, (core dumped)).
Built-ins — cd, echo, env, setenv, unsetenv, alias, history, exit.
Interactive prompt — raw-mode terminal, cwd-aware prompt, arrow-key history, Ctrl-L/Ctrl-U.
Command substitution — backticks, captured by recursively re-entering the shell's evaluator with stdout redirected.
Aliases — loaded at startup from .myshrc in the working directory.
Tests — 151 Criterion unit tests covering the operator tree, environment manipulation, cd
error paths and signal translation.
Requires a Unix-like system, make, a C compiler and the ncurses development headers.
git clone https://github.com/AntoinePoisson/myShell.git
cd myShell
make
./myshmake tests_run builds and runs the Criterion suite; make debug rebuilds with -g3 under
valgrind.
The Makefile's
CFLAGScontains--extra, which no current compiler accepts —-Wextrawas the intent. Building the original sources therefore needsmake CFLAGS="-I ./includes/ -Wall -Wextra -pedantic". Left as-is on purpose.
/bin/echo a | /usr/bin/tr a-z A-Z # pipeline
/bin/echo text > out.txt # redirection
/bin/cat < out.txt # input redirection
/usr/bin/true && /bin/echo success # conditional execution
echo `/bin/echo substituted` # backtick substitution
echo $? # last exit statusThis is a teaching implementation, not a POSIX shell. There is no variable expansion, no
globbing and no job control; quoting is handled by echo rather than by the parser, and
&&/|| group right where POSIX groups left. Built-ins invoked inside a pipeline run in the
forked child, so their effect on shell state is lost.
Individual project, written in 2018 during the Epitech curriculum and imported here in 2019. The source has intentionally not been modernised or refactored — its value is as a record of what was built, and the documentation exists to make that record legible.
MIT.
