| includes | ||
| libft | ||
| srcs | ||
| ignoreliberror | ||
| launch_minishell | ||
| Makefile | ||
| README.md | ||
Minishell - École 42
Description
Minishell est un projet de l'École 42 qui consiste à créer un shell Unix minimaliste mais fonctionnel, similaire à bash. Ce projet permet de comprendre en profondeur le fonctionnement des shells, la gestion des processus, et l'exécution de commandes sous Unix.
Objectifs pédagogiques
- Maîtriser la programmation système Unix/Linux
- Comprendre l'exécution de processus (fork, exec, wait)
- Gérer les pipes et redirections d'I/O
- Implémenter un parser pour analyser les commandes
- Traiter les signaux système (SIGINT, SIGQUIT)
- Gérer les variables d'environnement
Fonctionnalités implémentées
Built-ins
echoavec option-ncdavec chemins relatifs et absoluspwd- affichage du répertoire courantexport- définition de variables d'environnementunset- suppression de variablesenv- affichage de l'environnementexit- fermeture du shell avec code de retour
Fonctionnalités shell
- Exécution de programmes via PATH ou chemin absolu
- Pipes (
|) pour chaîner les commandes - Redirections :
<redirection d'entrée>redirection de sortie>>redirection de sortie en mode append<<here document avec délimiteur
- Variables d'environnement (
$VAR,$?,$$) - Gestion des quotes simples et doubles
- Historique des commandes
- Autocomplétion basique
Gestion des signaux
Ctrl+C(SIGINT) - interruptionCtrl+D(EOF) - fermeture propreCtrl+\(SIGQUIT) - ignoré en mode interactif
Technologies utilisées
- Langage : C (norme 42)
- Bibliothèques : readline, termcap
- Appels système : fork, execve, wait, pipe, dup2
- Gestion mémoire : malloc, free (pas de leaks)
Architecture du projet
Structure des fichiers
Minishell/
├── Makefile # Compilation
├── includes/ # Headers (.h)
│ ├── minishell.h # Header principal
│ └── libft.h # Bibliothèque libft
├── srcs/ # Code source
│ ├── main.c # Point d'entrée
│ ├── parsing/ # Analyseur lexical/syntaxique
│ │ ├── lexer.c
│ │ ├── parser.c
│ │ └── expander.c
│ ├── execution/ # Exécution des commandes
│ │ ├── executor.c
│ │ ├── pipes.c
│ │ └── redirections.c
│ ├── builtins/ # Commandes intégrées
│ │ ├── echo.c
│ │ ├── cd.c
│ │ ├── pwd.c
│ │ ├── export.c
│ │ ├── unset.c
│ │ ├── env.c
│ │ └── exit.c
│ ├── signals/ # Gestion des signaux
│ │ └── signals.c
│ └── utils/ # Fonctions utilitaires
│ ├── env_utils.c
│ ├── error.c
│ └── cleanup.c
└── libft/ # Bibliothèque personnelle
Flux d'exécution
- Lecture de la ligne de commande (readline)
- Tokenisation et analyse lexicale
- Parsing et construction de l'AST
- Expansion des variables et wildcards
- Exécution avec gestion des processus
- Nettoyage mémoire et gestion d'erreurs
Installation et compilation
Prérequis
- GCC compiler
- Make
- Bibliothèque readline (
sudo apt-get install libreadline-dev)
Compilation
git clone <repository-url>
cd Minishell
make
Nettoyage
make clean # Supprime les fichiers .o
make fclean # Supprime tout + l'exécutable
make re # Recompile entièrement
Utilisation
Lancement
./minishell
Exemples de commandes
# Commandes simples
$ ls -la
$ pwd
$ echo "Hello World"
# Pipes
$ cat file.txt | grep "pattern" | wc -l
$ ls | head -5
# Redirections
$ echo "test" > output.txt
$ cat < input.txt
$ ls >> log.txt
# Here document
$ cat << EOF
> line 1
> line 2
> EOF
# Variables d'environnement
$ export MY_VAR="value"
$ echo $MY_VAR
$ echo $? # Code de retour dernière commande
$ echo $$ # PID du shell
# Built-ins
$ cd /home/user
$ pwd
$ env | grep PATH
$ unset MY_VAR
$ exit 0
Gestion des quotes
$ echo "Hello $USER" # Expansion dans les doubles quotes
$ echo 'Hello $USER' # Pas d'expansion dans les simples quotes
$ echo "He said 'hello'" # Imbrication de quotes
Gestion d'erreurs
Types d'erreurs gérées
- Commandes introuvables (command not found)
- Permissions insuffisantes (permission denied)
- Fichiers inexistants (no such file or directory)
- Erreurs de syntaxe (syntax error)
- Erreurs de pipe (broken pipe)
- Allocation mémoire (malloc failure)
Codes de retour
0- Succès1- Erreur générale2- Erreur de syntaxe126- Permission refusée127- Commande introuvable130- Interruption par signal
Parsing et analyse
Étapes du parsing
- Tokenisation : Division en tokens (mots, opérateurs)
- Classification : Identification du type de chaque token
- Validation syntaxique : Vérification de la grammaire
- Construction AST : Arbre syntaxique abstrait
- Expansion : Variables, quotes, wildcards
Grammaire simplifiée
command_line : pipeline
pipeline : command ('|' command)*
command : simple_command redirection*
simple_command : word word*
redirection : '<' word | '>' word | '>>' word | '<<' word
Gestion mémoire
Stratégies appliquées
- Allocation tracking : Suivi de toutes les allocations
- Cleanup systématique : Libération en cas d'erreur
- Valgrind clean : Aucun leak détecté
- Error handling : Gestion robuste des échecs malloc
Tests et validation
Tests automatisés
# Tests de base
make test
# Tests avec valgrind
make test_memory
# Tests de régression
make test_all
Cas de test couverts
- Commandes simples et complexes
- Pipes multiples
- Redirections combinées
- Gestion d'erreurs
- Variables d'environnement
- Signaux et interruptions
Optimisations
Performance
- Parser optimisé pour les cas courants
- Gestion mémoire efficace
- Exécution directe des built-ins
- Cache PATH pour les exécutables
Compatibilité
- POSIX compliance pour les fonctionnalités de base
- Bash-like behavior pour l'expérience utilisateur
- Cross-platform (Linux, macOS)
Compétences développées
- Programmation système avancée Unix/Linux
- Gestion des processus et communication inter-processus
- Parsing et analyse syntaxique
- Architecture logicielle modulaire
- Debugging multi-processus
- Gestion mémoire rigoureuse sans leaks
- Tests et validation de systèmes complexes
Contraintes et normes 42
- Norme de codage 42 strictement respectée
- Pas de variables globales (sauf une pour les signaux)
- Gestion d'erreurs exhaustive
- Pas de memory leaks (validé Valgrind)
- Fonctions autorisées uniquement celles de la liste 42
Challenges techniques
Difficultés rencontrées
- Parsing complexe avec gestion des quotes et échappements
- Gestion des signaux dans un contexte multi-processus
- Race conditions entre processus père et fils
- Memory management dans un contexte d'erreurs multiples
- Compatibilité bash pour les edge cases
Solutions apportées
- Architecture modulaire facilitant la maintenance
- Error handling centralisé et robuste
- Tests exhaustifs couvrant les cas limites
- Documentation du code pour la compréhension
Auteur
Alexandre Pommier (apommier) - École 42
Licence
Projet académique - École 42