42sh is a Unix shell implementation written in C, developed as part of the EPITA curriculum. It aims to replicate the behavior of a POSIX-compliant shell (sh/bash), supporting a full pipeline from lexing and parsing to AST construction and execution. This project was realized by students within a one-month timeframe as part of their school curriculum, and as such, it may not be perfect or fully complete.
The shell is built around a classic compiler-like architecture: source input is tokenized by the lexer, parsed into an AST by the parser, and then evaluated by the execution engine. It supports interactive use as well as script execution.
- Lexer — tokenizes raw shell input including keywords, operators, quotes, and redirections
- Parser — builds an Abstract Syntax Tree (AST) from the token stream following POSIX grammar
- AST execution engine — walks and evaluates the AST node by node
- Control flow —
if/elif/else/fi,while,until,forloops with properbreak/continue - Pipelines —
|operator with correct fd wiring between processes - Redirections —
>,>>,<,<>,>&,2>&1, fd duplication and closing - Logical operators —
&&and||with short-circuit evaluation - Negation —
!prefix operator - Subshells —
( )with isolated environment - Brace groups —
{ }command blocks - Variables — assignment, expansion (
$VAR,${VAR}), special variables ($?,$$,$#,$@,$*,$0–$9) - Quoting — single quotes (literal), double quotes (with expansion), backslash escaping
- Command substitution —
`cmd`and$(cmd) - Functions — definition and call, local positional parameters,
return - Built-in commands —
echo,cd,exit,export,unset,true,false,.(dot/source),break,continue - Comments —
#comment support - Pretty printer — AST pretty-printing for debugging
- Test suite — comprehensive integration and unit tests
└── 69sh/
├── 69sh/
│ ├── configure.ac # Autotools configuration
│ ├── Makefile.am # Top-level Makefile template
│ ├── author_setup.sh # Author/environment setup script
│ ├── pretty_print.sh # Pretty-print helper script
│ └── src/
│ ├── 42sh.c # Entry point (main)
│ ├── lexer/ # Tokenizer
│ ├── parser/ # Grammar rules → AST
│ ├── ast/ # AST node constructors + pretty printer
│ ├── exec/ # AST execution engine
│ ├── vars/ # Variable storage and expansion
│ ├── funcs/ # Shell function registry
│ └── io/ # I/O helpers
└── tests/
├── testsuite.sh # Main test runner
├── lib/runner.sh # Test runner library
├── basics/ # Integration tests (step1, step2, step3)
└── unitary/ # Unit tests (lexer, builtins, options)42SH/
src/
| Module | Description |
|---|---|
42sh.c |
Entry point — handles argument parsing, REPL loop, and script mode |
lexer/ |
Transforms raw input into a stream of tokens (words, keywords, operators, redirections, quotes) |
parser/ |
Recursive-descent parser implementing the POSIX shell grammar; produces an AST |
ast/ |
AST node types and constructors for every shell construct (cmd, if, for, while, until, pipe, redir, block, subshell, func, operator, negation, list) |
ast/pretty_printer/ |
Walks the AST and prints a human-readable representation for debugging |
exec/ |
Evaluates the AST: forks processes, sets up pipes, redirections, and executes builtins or external commands |
vars/ |
Shell variable storage (get/set/unset), expansion of $VAR, ${VAR}, and special variables |
funcs/ |
Registry for user-defined shell functions (store and look up by name) |
io/ |
Low-level I/O utilities used across the shell |
tests/
| Directory | Description |
|---|---|
basics/step1/ |
Builtins (echo), simple commands, comments, if/elif/else, lists |
basics/step2/ |
Double quotes, variables, for, while/until, pipes, redirections, operators, negation |
basics/step3/ |
Blocks, subshells, functions, command substitution, break/continue, cd, exit, export/unset, dot builtin |
unitary/ |
Unit tests for the lexer, option handling, and specific builtins |
- C compiler:
gccorclang - Autotools:
autoconf,automake,libtool - make
On Debian/Ubuntu:
sudo apt-get install build-essential autoconf automake libtool-
Clone the repository:
git clone https://github.com/69sh-epita/69sh cd 69sh/69sh -
Bootstrap the build system:
autoreconf -i
-
Configure:
./configure
-
Build:
make
The compiled binary will be available as src/42sh.
Interactive mode:
./src/42shScript mode:
./src/42sh script.shCommand string:
./src/42sh -c "echo hello world"The project includes a shell-based test suite. From the 69sh/ directory:
cd tests
./testsuite.shTo run only a specific category (e.g. step2 variables):
./testsuite.sh basics/step2/variablesUnit tests are located in tests/unitary/ and follow a .t format compatible with the runner in tests/lib/runner.sh.
- Lexer — tokenization of all POSIX shell constructs
- Parser — recursive-descent grammar, AST construction
- Execution engine — commands, pipes, redirections, control flow
- Variables & expansion — assignment,
$VAR, special variables - Built-ins —
echo,cd,exit,export,unset,break,continue,. - Functions — definition, call, local args,
return - Subshells & blocks —
( )and{ } - Command substitution —
`cmd`and$(cmd) - Here-documents —
<<EOF - Arithmetic expansion —
$(( )) - Job control —
&,fg,bg,jobs - Signal handling —
trap
- EPITA — for the project specification and curriculum framework
- The POSIX shell standard — IEEE Std 1003.1
- Contributors of the
69sh-epitaorganization : Anatole Debus, Etân Delabie, Martin Vitte, Aymeric Leclerre