minishell is a small interactive Unix shell written in C. meant as a recreational project that reproduces the core command-processing behavior of Bash
that includes: prompt handling, command history, quoting, environment
expansion, pipelines, redirections, built-in commands, and signal-aware process
execution.
The project is primarily an exercise in parsing and Unix process control. Input is not executed directly, it goes through multiple steps: tokenized, expanded, converted into an abstract syntax tree (AST), and then evaluated by the execution layer.
- Interactive prompt with the current working directory and Readline history.
- Executable lookup through
PATH, plus relative and absolute command paths. - Single and double quotes.
- Environment variable expansion (
$NAME) and exit-status expansion ($?). - command pipelines using
|. - Input redirection with
<. - Output truncation and append redirection with
>and>>. - Here-documents with
<<. - Exit-status propagation from commands, pipelines, and signals.
- Interactive handling of
Ctrl-C,Ctrl-\, and end-of-file (Ctrl-D).
The following built-ins are implemented:
| Built-in | Behavior |
|---|---|
echo |
Prints arguments; accepts repeated valid -n options |
cd |
Changes directory and updates PWD and OLDPWD |
pwd |
Prints the current working directory |
export |
Adds or updates environment variables; lists them without arguments |
unset |
Removes environment variables |
env |
Prints the current environment |
exit |
Exits with optional numeric status validation |
This is not intended to be a complete POSIX or Bash implementation. Features
outside the current grammar include logical operators (&&, ||), command
lists (;), subshells, wildcard expansion, job control, and command
substitution.
It is however built in a flexible way and designed to make it easier to add more operators and components to it.
Each non-empty input line passes through four distinct stages:
- Tokenization identifies words, pipes, and redirection operators while validating quote and operator syntax.
- Expansion resolves environment variables and
$?, preserves quoting semantics, and splits expanded unquoted text into tokens. - AST generation represents commands, redirections, and pipelines as a tree instead of relying on ad hoc string processing.
- Execution applies redirections, dispatches built-ins, creates pipes and child processes, resolves executable paths, and records the final status.
.
├── Makefile
├── libft/ custom C utility library and ft_printf
└── main/
├── messh.c initialization, signals, and entry point
├── core.c read-evaluate loop
├── tokenizer/ lexical analysis and syntax validation
├── expansion/ variables, exit status, and quote removal
├── ast_generator/ AST construction and node definitions
├── execution/
│ ├── built_in/ shell built-ins
│ ├── cmd_execute/ external command dispatch
│ ├── environment/ internal environment representation
│ ├── pipe/ pipeline process management
│ └── redirection/ files and here-documents
└── memory/ token and AST cleanup
Runtime state is held in a central t_context, which owns the current line,
token list, AST, environment list, exit status, and execution bookkeeping.
The environment is copied into a linked list at startup and converted back to an
envp-style array when an external command is launched.
- A Linux or compatible Unix-like environment
ccwith C compilation support- GNU Make
- GNU Readline development headers and library
Install the build dependencies for your distribution:
Void Linux
sudo xbps-install -S base-devel readline-develDebian/Ubuntu
sudo apt install build-essential libreadline-devFedora
sudo dnf install gcc make readline-develArch Linux
sudo pacman -S --needed base-devel readlineBuild the shell from the repository root:
make
./minishellThe Makefile compiles with -Wall -Wextra -Werror and links the local libft and Readline libraries.
Available maintenance targets:
make clean # remove object files
make fclean # remove object files, libraries, and the binary
make re # perform a clean rebuildecho "user: $USER"
printf "alpha\nbeta\n" | grep beta | wc -l
cat < input.txt > output.txt
echo first > log.txt
echo second >> log.txt
cat << EOF
current directory: $PWD
EOF
export PROJECT=minishell
env | grep PROJECT
echo $?- Built-ins execute in the current process when used as a standalone command,
allowing state-changing operations such as
cd,export, andunsetto persist. Within a pipeline they execute in a child process. - Pipeline status follows the rightmost command, consistent with conventional shell behavior.
- Standard input and output are duplicated before command execution and restored afterward, so redirections do not leak into the next prompt cycle.
- Here-document input is collected before AST execution and stored in a restricted temporary file used as redirected standard input.
- The code uses a project-level allocation collector alongside explicit cleanup for tokens, AST nodes, environment entries, and process resources.
The repository does not currently include an automated test suite or a CI configuration. validation should therefore compare interactive results and exit statuses against Bash for syntax that lies within the supported feature set.