"minishell" is a project at 42 Madrid that involves creating a simple shell that replicates basic functionalities of bash. This project introduces command parsing, process management, signal handling, and teaches how to implement a command-line interpreter in a systematic way.
The goal is to implement a shell program that can execute commands, manage environment variables, handle redirections and pipes, and provide a user-friendly interactive experience similar to bash.
- Understanding and implementing command-line parsing and tokenization
- Learning about process creation and management with fork() and execve()
- Managing pipes and redirections for inter-process communication
- Implementing built-in shell commands
- Handling signals (SIGINT, SIGQUIT, EOF)
- Managing environment variables and shell variables
- Implementing command history functionality
- Handling quotes and special characters properly
minishell
Description: A minimal shell implementation that mimics bash behavior
Usage: ./minishell or ./minishell -c "command"
Behavior: Reads and executes commands interactively or from arguments
int main(int argc, char **argv, char **envp);The implementation of minishell requires creating processes and handling signals. For this, several system calls are used:
The main system calls and functions are:
fork()β Creates a child process to execute commands.
pid_t pid = fork();execve()β Replaces the current process with a new program.
execve(cmd_path, cmd_args, envp);pipe()β Creates a pipe for communication between processes.
int pipefd[2];
pipe(pipefd);dup2()β Duplicates file descriptors for redirection.
dup2(fd, STDIN_FILENO);signal()/sigaction()β Sets up signal handlers for Ctrl-C, Ctrl-, etc.
signal(SIGINT, signal_handler);readline()β Reads a line from the terminal with line editing capabilities.
char *line = readline("minishell> ");add_history()β Adds a command to the history list.
add_history(line);These functions are essential for implementing minishell, as they allow command execution, process management, and user interaction.
Features and Behavior
- Prompt: Displays custom prompt with
user@hostname:path (git_branch) $ - Command execution: Supports absolute paths, relative paths, and PATH resolution
- History: Full command history navigation with up/down arrows
- Signals: Proper handling of:
Ctrl-C: Interrupts current command (SIGINT)Ctrl-D: Exits shell when line is empty (EOF)Ctrl-\: Does nothing in interactive mode (SIGQUIT)
Environment Variables:
$VAR- Environment variable expansion$?- Exit status of last command$0- Shell name$$- Shell process ID$_- Last argument of previous command
Redirections:
<- Input redirection>- Output redirection (truncate)>>- Output redirection (append)<<- Heredoc (read until delimiter)
Pipes:
|- Connect output of one command to input of another
Quotes:
'single quotes'- Preserve literal value of all characters"double quotes"- Preserve literal value except$and\
echo [-n]- Print arguments to stdoutcd [path]- Change working directorypwd- Print working directoryexport [var=value]- Set environment variablesunset [var]- Unset environment variablesenv- Display environment variablesexit [n]- Exit shell with status code
./minishell -c "command"
# Executes command and exitsπ₯ Download & Compilation
# Clone the repository
git clone https://github.com/ravazque/minishell.git
cd minishell
# Compile the program
make
# Clean object files
make clean
# Clean everything including executable
make fclean
# Recompile everything
make re
# Run the program
./minishellπ Project Structure
minishell/
ββββ¬ include/
β βββ colors.h # Color definitions for terminal output
β βββ minishell.h # Main header with prototypes and structures
ββββ¬ src/
β βββ minishell.c # Main entry point
β ββββ¬ aux_libft/ # Custom library functions
β β βββ include/ # Library headers
β β βββ src/ # Library implementations
β ββββ¬ aux_minishell/ # Auxiliary minishell functions
β β βββ error.c # Error handling
β β βββ init.c # Initialization routines
β β βββ loop.c # Main shell loop
β β βββ mshlvl.c # Shell level management
β β βββ underscore.c # $_ variable handling
β ββββ¬ built_ins/ # Built-in commands
β β βββ builtin_echo.c # echo command
β β βββ builtin_exit.c # exit command
β β βββ builtin_pwd.c # pwd command
β β βββ builtin_unset.c # unset command
β β βββ builtins_core.c # Core built-in dispatcher
β β βββ builtins_utils.c # Built-in utilities
β β ββββ¬ builtin_cd/ # cd command implementation
β β β βββ builtin_cd.c # Main cd logic
β β β βββ builtin_cd_path.c # Path resolution
β β β βββ builtin_cd_utils.c # cd utilities
β β ββββ¬ builtin_env/ # env command implementation
β β β βββ builtin_env.c # Main env logic
β β β βββ builtin_env_cmd.c # env command parsing
β β β βββ builtin_env_exec.c # env execution
β β β βββ builtin_env_fork.c # env fork handling
β β β βββ builtins_setenv.c # Environment variable setter
β β ββββ¬ builtin_export/ # export command implementation
β β βββ builtin_export.c # Main export logic
β β βββ builtin_export_print.c # Print exported variables
β β βββ builtin_export_set.c # Set exported variables
β β βββ builtin_export_utils.c # Export utilities
β β βββ builtin_export_validate.c # Export validation
β ββββ¬ cleaner/ # Memory cleanup functions
β β βββ cleanup_exec.c # Execution cleanup
β β βββ cleanup.c # General cleanup
β β βββ free_structs.c # Structure deallocation
β ββββ¬ execution/ # Command execution
β β ββββ¬ executor/ # Main executor
β β β βββ exec_empty.c # Funcions for empty commands
β β β βββ exec_child.c # Child process execution
β β β βββ exec_env.c # Environment for execution
β β β βββ exec_path.c # Path resolution
β β β βββ exec_pipes.c # Pipe management
β β β βββ exec_single.c # Single command execution
β β β βββ exec_utils.c # Execution utilities
β β β βββ exec_wait.c # Process wait handling
β β β βββ executor.c # Main executor logic
β β ββββ¬ heredocs/ # Heredoc implementation
β β β βββ heredocs_collect.c # Line collection
β β β βββ heredocs.c # Main heredoc logic
β β β βββ heredocs_handler.c # Heredoc handlers
β β ββββ¬ redirs/ # Redirection handling
β β βββ redirections.c # Redirection setup
β ββββ¬ fork_bomb/ # Fork bomb detection
β β βββ fork_bomb.c # Fork bomb handler
β β βββ fork_bomb_utils.c # Detection utilities
β ββββ¬ parse/ # Input parsing
β β βββ parse.c # Main parser
β β βββ parse_assign.c # Assignment parsing
β β βββ parse_utils.c # Parser utilities
β β ββββ¬ expand/ # Variable expansion
β β β βββ expand.c # Main expander
β β β βββ expand_extract.c # Variable extraction
β β β βββ expand_redirs.c # Redirection expansion
β β β βββ expand_str.c # String expansion
β β β βββ expand_tilde.c # Tilde expansion
β β β βββ expand_utils.c # Expansion utilities
β β β βββ expand_vars.c # Variable expansion
β β β ββββ¬ expand_split/ # Word splitting
β β β βββ expand_split.c # Main word splitter
β β β βββ expand_split_add.c # Add split tokens
β β β βββ expand_split_count.c # Count split words
β β β βββ expand_split_helpers.c # Split helpers
β β β βββ expand_split_utils.c # Split utilities
β β β βββ expand_split_word.c # Word extraction
β β ββββ¬ lexer/ # Lexical analysis
β β β βββ lexer.c # Main lexer
β β β βββ lexer_classify.c # Token classification
β β β βββ lexer_cmd_create.c # Command creation
β β β βββ lexer_pipe_split.c # Pipe splitting
β β β βββ lexer_pipe_valid.c # Pipe validation
β β β βββ lexer_quotes.c # Quote handling
β β β βββ lexer_redir.c # Redirection tokens
β β β βββ lexer_redir_proc.c # Redirection processing
β β β βββ lexer_token.c # Token creation
β β β βββ lexer_token_arr.c # Token array conversion
β β β βββ lexer_utils.c # Lexer utilities
β β ββββ¬ tokenizer/ # Tokenization
β β βββ tokenizer.c # Main tokenizer
β β βββ tokenizer_handlers.c # Character handlers
β β βββ tokenizer_helpers.c # Helper functions
β β βββ tokenizer_parts.c # Token parts handling
β β βββ tokenizer_utils.c # Tokenizer utilities
β ββββ¬ prompt/ # Prompt generation
β β βββ prompt.c # Main prompt builder
β β βββ prompt_git.c # Git branch detection
β β βββ prompt_path.c # Path formatting
β β βββ prompt_utils.c # Prompt utilities
β ββββ¬ signals/ # Signal handling
β βββ signals.c # Main signal setup
β βββ signal_handlers.c # Signal handlers
βββ Makefile # Compilation rules
βββ README.md # Project documentation
The minishell project teaches advanced system programming and shell implementation concepts:
- Process Management: Understanding fork(), execve(), and wait() system calls
- Command Parsing: Learning to tokenize and parse complex command-line syntax
- Signal Handling: Proper management of SIGINT, SIGQUIT, and EOF signals
- File Descriptor Management: Deep knowledge of redirections and pipes
- Environment Management: Manipulating and maintaining environment variables
- Error Handling: Robust error checking and proper exit codes
- Memory Management: Preventing leaks in a complex interactive program
- Language: C (C90 standard)
- Compiler: cc with flags
-Wall -Wextra -Werror - System Calls: fork(), execve(), pipe(), dup2(), waitpid(), signal()
- External Functions: readline(), add_history() (GNU Readline library)
- Platform: UNIX-like systems (Linux, macOS)
- Memory Management: Proper cleanup of all allocated memory and file descriptors
- Process Handling: Parent-child process synchronization and signal propagation
- Exit Codes: Proper exit status propagation and
$?handling
Note
This project serves as a comprehensive introduction to shell programming and demonstrates proficiency in process management parsing, and inter-process communication concepts.