This project has been created as part of the 42 curriculum by arouland and ymoumene.
Minishell is a command-line interpreter written in C and inspired by Bash. The goal of the project is to understand how a shell works internally by implementing command parsing, process creation, pipes, redirections, signal handling and environment management.
The program displays an interactive prompt, reads and interprets the user's commands, then executes built-ins or external programs. It supports quoted arguments, environment-variable expansion, command history, pipelines and the usual input and output redirections.
The bonus part adds logical operators, grouped commands and wildcard expansion.
- Interactive prompt and command history using GNU Readline.
- Execution of commands found through
PATH. - Execution through absolute and relative paths.
- Single and double quote handling.
- Expansion of environment variables such as
$USER. - Expansion of the last command status through
$?. - Pipelines using
|. - Input redirection using
<. - Output redirection using
>. - Output redirection in append mode using
>>. - Here-documents using
<<. - Context-dependent handling of
Ctrl-C,Ctrl-DandCtrl-\. - Multiline input for unfinished quotes, operators and parentheses.
echowith the-noption.cdwith a relative or absolute path.pwdwithout options.exportwithout options.unsetwithout options.envwithout options or arguments.exitwith an optional numeric argument and without options.
- Logical AND with
&&. - Logical OR with
||. - Grouped commands and subshells using
(and). - Wildcard expansion using
*in the current directory.
- Linux, macOS or another Unix-like environment.
- A C compiler available as
cc. make.- GNU Readline and its development headers.
The Makefile compiles the project with -Wall -Wextra -Werror.
On Debian or Ubuntu, Readline can be installed with:
sudo apt install libreadline-devOn macOS with Homebrew:
brew install readlineFrom the repository root:
makeThis creates the minishell executable.
The Makefile also provides a bonus target, which creates
minishell_bonus from the complete source set:
make bonusUseful Makefile targets are:
make clean # Remove object files
make fclean # Remove object files, libraries and executables
make re # Clean and rebuild the projectLaunch the shell without arguments:
./minishellThe interactive prompt is then displayed:
minishell$
Run exit or press Ctrl-D on an empty prompt to leave the shell.
minishell$ pwd
minishell$ export PROJECT=minishell
minishell$ echo "Current project: $PROJECT"
minishell$ echo '$PROJECT is not expanded inside single quotes'
minishell$ unset PROJECTminishell$ printf "one\ntwo\nthree\n" | grep t | wc -l
minishell$ echo "first line" > output.txt
minishell$ echo "second line" >> output.txt
minishell$ cat < output.txtminishell$ cat << EOF
> Hello $USER
> EOFQuoting the delimiter disables variable expansion inside the here-document:
minishell$ cat << 'EOF'
> $USER is kept as written
> EOFminishell$ false || echo "the first command failed"
minishell$ true && echo "the first command succeeded"
minishell$ (echo first && echo second) | wc -l
minishell$ cd srcs/exec && echo *.cCommands can be compared with Bash to verify output and exit statuses:
# Run in Bash
bash
echo "$USER" | wc -c
echo $?
# Leave Bash, launch Minishell and repeat the same commands
exit
./minishell
echo "$USER" | wc -c
echo $?The shell also accepts commands through standard input, which is useful for small smoke tests:
printf '%s\n' 'echo hello' 'pwd | wc -c' 'exit' | ./minishellUseful cases to test include:
- Empty input and whitespace-only input.
- Quoted and unquoted environment variables.
- Commands that exist and commands that do not exist.
- Several consecutive pipes.
- Redirections before and after command arguments.
- Multiple here-documents.
- Built-ins inside and outside pipelines.
Ctrl-C,Ctrl-DandCtrl-\at the prompt and during a command.- Logical operators, subshells and wildcard expansion.
-
Lexer and parser: the input is split into typed tokens before syntax validation. The parser then builds a linked list of command nodes containing arguments, redirections and the operator leading to the next command.
-
Execution: pipelines are created with
pipe,forkanddup2. External commands are launched withexecve. Built-ins that modify the shell state are executed in the parent process when they are not part of a pipeline. -
Environment: environment variables are stored in a linked list so that
export,unsetandcdcan update the shell state during execution. The special?entry stores the latest exit status for$?expansion. -
Signals: the prompt, child processes and here-documents use different signal configurations to reproduce Bash-like interactive behaviour.
-
Resource management: dynamically allocated memory and tracked file descriptors are registered in dedicated garbage-collector lists and released between commands or before a child process exits.
.
├── includes
│ ├── libft
│ │ ├── ft_printf
│ │ ├── libft.h
│ │ └── Makefile
│ └── minishell.h
├── srcs
│ ├── built_in
│ ├── env
│ ├── exec
│ │ └── heredoc
│ ├── expand
│ │ └── wildcards
│ ├── free
│ ├── main_utils
│ ├── parsing
│ │ ├── check_syntax
│ │ └── lexer
│ ├── signals
│ └── main.c
├── Makefile
└── README.md
srcs/parsing/: tokenization, syntax validation and command construction.srcs/expand/: quote removal, variable expansion and wildcard matching.srcs/exec/: processes, pipelines, redirections and here-documents.srcs/built_in/: implementation of the seven required built-ins.srcs/env/: creation and modification of the shell environment.srcs/signals/: signal handlers for each execution context.srcs/free/: memory and file-descriptor cleanup.includes/libft/: our recreation of standard c functions (42 requirements).
- GNU Bash Reference Manual: shell syntax, expansions, redirections and built-ins.
- GNU Readline Documentation: interactive input and command history.
- Linux manual pages: documentation for
fork(2),execve(2),wait(2),pipe(2),dup2(2),sigaction(2)and other system calls. - Minishell 42: l'art de créer un shell performant et maintenable: article by Dylan Gibrat.
Artificial intelligence was used as a support tool during the project for:
- clarifying shell parsing, process and signal-handling concepts;
- the creation of manual test cases;
- reviewing and improving the project documentation.