Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

229 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Minishell - 42 Project

📘 Introduction

The Minishell project at 42 challenges students to build a basic Unix shell from scratch using the C programming language. This shell must replicate the behavior of Bash for a subset of its features, including parsing, environment management, redirections, and piping — all while handling user input interactively and robustly.

The project emphasizes process management, signal handling, lexing and parsing, and advanced data structures, such as an Abstract Syntax Tree (AST).


Concept

The goal of Minishell is to create a functional shell with behavior that closely resembles /bin/bash in terms of supported features. The shell should support:

  • Tokenization and Parsing using an Abstract Syntax Tree (AST)
  • Execution of commands with redirections and pipes
  • Signal handling (e.g., Ctrl+C, Ctrl+\)
  • Environment variable management (export, unset, etc.)
  • Built-in commands

Each shell cycle follows:

read → parse → execute → wait → repeat


Mandatory Requirements

Your shell must:

  • Display a prompt and wait for user input
  • Implement lexer to tokenize input and parser to build the AST
  • Execute commands from the AST with correct handling of:
    • Redirections: >, >>, <, <<
    • Pipes: |
  • Implement the following built-in commands:
    • echo, cd, pwd, export, unset, env, exit
  • Properly manage environment variables (envp)
  • Handle errors gracefully (e.g., invalid syntax, command not found)
  • Exit cleanly on Ctrl+D and respond to Ctrl+C appropriately

Input Handling and Parsing

  • Input is read using readline()
  • Tokenization respects quotes (', ") and escape characters
  • Parsing is done recursively via a binary tree-based AST
  • The tree organizes operators (pipes/redirections) and command nodes

🌲 AST Design (Abstract Syntax Tree)

The parser builds an AST where:

  • Each node represents a command, redirection, pipe, or logical operator.
  • Left/right children represent left/right sides of compound commands.

This design enables:

  • Recursive command execution.
  • Natural support for parentheses and complex shell logic.

Example:

echo hello | grep h && ls > out.txt

Yields an AST like:

         &&
       /    \
      |     >
     / \   / \
echo grep ls out.txt

Execution follows post-order traversal of this tree structure.


Implementation Details

Execution

  • Commands are executed via fork() and execve()
  • Built-ins are executed in the parent process (except in pipelines)
  • Pipes and redirections are managed using dup2(), open() and close()
  • Exit codes are tracked and used for conditionals (like &&, || in bonus)

Signal Handling

  • SIGINT (Ctrl+C): should interrupt and display a new prompt
  • SIGQUIT (Ctrl+\): should be ignored
  • SIGTERM and EOF are handled gracefully

Redirection Handling

  • >: redirect output to a file (overwrites the file if it already exists)
  • >>: append output to a file
  • <: read input from a file
  • <<: here-document (read input in real-time until it finds the given delimiter)

✨ Bonus Features

For the minishell_bonus version:

  • Support for && and || conditional execution
  • Handle parentheses for grouped commands: (cmd1 && cmd2) || cmd3
  • Wildcards (*) via globbing

⚙️ Compilation & Usage

🛠 Compilation

make

▶️ Running

./minishell

You'll see a custom prompt (e.g., minishell$) awaiting input.

🧪 Example Usage

minishell$ export PATH=$PATH:/usr/bin
minishell$ echo "Hello World"
minishell$ ls -l | grep minishell >> logs.txt
minishell$ cat logs.txt
minishell$ exit

To clean compiled objects:

make clean

To clean everything including the binary:

make fclean

To recompile from scratch:

make re

⚠️ Common Pitfalls

  • $\color{Crimson}{\textbf{Improper quoting}}$ → Ensure correct token handling inside quotes
  • $\color{Crimson}{\textbf{Unclosed pipes or redirs}}$ → Syntax errors must be handled
  • $\color{Crimson}{\textbf{Zombie processes}}$ → Always wait() for children
  • $\color{Crimson}{\textbf{Memory leaks}}$ → Free all memory after each command cycle
  • $\color{Crimson}{\textbf{Bad fork logic}}$ → Don't fork built-ins unless necessary
  • $\color{Crimson}{\textbf{Unprotected global state}}$ → Use signal-safe logic

📚 Lessons Learned

  • Deepened understanding of Unix process lifecycle, including fork, exec, and wait
  • Learned how to implement signal-safe input handling
  • Built a recursive parser with AST, applying compiler theory principles
  • Managed complex memory and file descriptor lifecycles in C
  • Strengthened debugging and error-handling strategies

Conclusion

The Minishell project is a deep dive into systems programming, shell architecture, and process management. It gives real-world experience in writing a command interpreter, handling low-level operations, and structuring a program using an AST, making it a valuable step toward becoming a proficient systems developer.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages