elouann.dev
FR — version française

ProjectsSystems, network & algorithms

Minishell

A POSIX Bash replica

Period
Mar 2025 – May 2025
Context
42 curriculum
Team
group
Grade
101/100
  • C
  • Low-level
  • Imperative programming
  • Shell
  • CLI
  • Unix

View source

A Bash replica, built by two people, in C. From the line typed on the keyboard to the processes that run, we had to reproduce everything a shell does, including its strangest edge cases.

readlinethe linelexertokensparsercommandsexpansion$VAR, quotesexecfork / execve$ ls -l | grep .c > out.txtminishellparent, waitsfork()fork()ls -lexecvepipegrep .cexecveout.txtstdout = pipe[1]stdin = pipe[0]dup2(fd, 1)duplicated fds
DiagramAt the top, the journey of a command line. At the bottom, what really happens for a line with a pipe and a redirection.

Reading a line

The line is split into words and operators (lexer), then grouped into commands with their redirections (parser). Single and double quotes must be respected, variables such as $HOME or $? expanded, and the <, >, >> redirections and the << heredoc handled.

Running it

For a chain of piped commands, the shell creates the pipe()s, calls fork() once per command, wires inputs and outputs with dup2(), then starts the program with execve() after looking it up in PATH. Builtins (cd, echo, export, unset, env, pwd, exit) are written by hand, since some of them must change the shell itself.

Signals behave differently depending on the context: Ctrl+C clears the line at the prompt, interrupts a running command, and cancels a heredoc. All memory is freed on every cycle, and the environment is our own list, which works even when started with no environment at all.

On top of that

Four colour themes for the prompt, picked at launch with -t. It was also my first real two-person project: splitting parsing and execution required a clear definition of what goes from one to the other.

What I took away

  • fork, pipe, dup2, execve and waitpid: the heart of Unix fits in five calls.
  • One file descriptor left open can block an entire pipeline.
  • A clear interface between two parts of the code makes working as a pair easier.