This project has been created as part of the 42 curriculum by emercier, nmunari.
Minishell is a 42 project that involves creating a simple Unix shell. It is a simplified version of Bash, designed to help students understand processes and file descriptors.
The program displays a prompt, waits for user input, parses commands, and executes them. It supports built-in commands, pipes, redirections, and environment variable management. Additionally, this version includes bonus features: logical operators (&&, ||) with parenthesis for priorities, and wildcard (*) expansion for the current directory.
As per the project requirements, the following Bash commands have been re-implemented from scratch:
echowith option-ncdwith only a relative or absolute pathpwdwith no optionsexportwith no optionsunsetwith no optionsenvwith no options or argumentsexitwith no options
The project is compiled using a Makefile that handles dependencies and prevents unnecessary relinking. It compiles the source files using cc with the flags -Wall -Wextra -Werror.
The Makefile includes the following standard rules:
$(NAME)/all: Compiles the executable.clean: Removes object files.fclean: Removes object files and the executable.re: Recompiles the project from scratch.
To compile and launch:
make
./minishell
Once launched, Minishell provides an interactive prompt (e.g., minishell> ). You can type commands just like in Bash, including bonus features:
minishell> ls -l | grep .c
minishell> echo "Hello" > outfile && cat outfile
minishell> (ls | wc -l) && echo "Done"
minishell> ls *.c
minishell> exit
- Process Control (fork, exec, wait)
- Unix Signals Explained
- Bash Parser Logic & Grammar
- Minishell Tester
This project was developed with the assistance of AI to enhance learning and code quality. AI was used for:
- Concept Explanation: Acting as a virtual tutor to clarify detailed concepts and logic whenever I struggled to understand specific parts of the project.
- Documentation: Writing the English content of this README based on the structure and directives I provided in French.
To adhere to the project constraints and mimic Bash behavior, the implementation follows a "Read-Parse-Execute" loop (REPL):
The shell must interpret raw user input, handling complex syntax before execution.
- Tokenization: The input string is split into "tokens", identifying operators (
|,<,>,&&,||), parentheses, and words. - Wildcards: The
*token triggers a directory expansion, matching files in the current working directory. - Parsing & Priorities: A recursive descent parser (or equivalent logic) constructs an Abstract Syntax Tree (AST) to respect the priority of parenthesis and logical operators.
Executing commands involves managing system processes and controlling the flow based on logic.
- Process Management: The program uses
fork()to create child processes andexecve()to run binaries. - Redirections & Heredoc: Before execution, file descriptors are manipulated using
dup2()to handle standard redirections (<,>,>>) andhere-doc(<<) input. - Subshells: Commands enclosed in parentheses
( ... )are executed in a forked child process (subshell) to ensure environment isolation. - Logical Operators: The execution tree processes
&&and||nodes, executing the right branch only if the left branch succeeds (exit status 0) or fails, respectively.
The shell responds to user signals appropriately in both interactive and blocking modes.
- Interactive Mode:
Ctrl-Cresets the prompt,Ctrl-Dexits, andCtrl-\is ignored. - Blocking Mode: Signals are forwarded to child processes (e.g., stopping a running
grep), ensuring the shell waits correctly.