Minishell
minishell est mon premier gros projet de groupe du cursus 42 : réécrire un shell interactif (un “mini-bash”) en C, avec un comportement réaliste sur tout ce qui est essentiel au quotidien : parsing, expansions, redirections, pipelines, builtins et signaux.
Le projet force à comprendre ce que le shell fait réellement : transformer une ligne de commande en une exécution correcte de processus, avec les bons file descriptors, les bons exit codes, et une gestion robuste des erreurs.
Objectifs
- Construire un pipeline complet : lecture → lexer/parser → expander → exécution (processus/FD).
- Maîtriser les concepts systèmes :
fork/exec/wait,pipe,dup2, redirections, signaux. - Produire un programme stable : pas de crash, gestion propre des erreurs, pas de leaks (hors cas connus de
readline).
Fonctionnement
En lançant ./minishell, un prompt apparaît :
- La saisie est gérée via readline (historique, édition de ligne).
- La ligne est analysée (tokens, quotes, opérateurs).
- Les expansions sont appliquées (
$VAR,$?, et comportement des quotes). -
Le shell exécute :
-
soit un builtin dans le process du shell (ex :
cd,export…) - soit un binaire externe via
fork()+execve() - Les redirections et pipes sont branchés avec
dup2()/pipe().
Features clés
Parsing & quoting
- Gestion des quotes simples (
'...') : protège tout, aucune expansion. - Gestion des doubles quotes (
"...") : protège les métacaractères mais garde l’expansion$. - Refus / gestion d’erreurs sur les syntaxes non supportées par le sujet (ex. quotes non fermées).
Redirections & pipes
-
Redirections :
-
<input >output (truncate)>>output (append)<<heredoc (délimiteur)- Pipes
|: chaîner plusieurs commandes en connectant stdout → stdin.
Expansions
- Expansion des variables d’environnement :
$VAR→ valeur. - Expansion du code retour :
$?→ exit status de la dernière commande.
Builtins
Implémentation des commandes intégrées (selon sujet) :
echo(avec-n)cdpwdexportunsetenvexit
Signaux (comportement “bash-like”)
Ctrl-C: interrompt et ré-affiche un prompt propre.Ctrl-D: EOF → quitte le shell.Ctrl-\: comportement conforme au sujet (pas de quit sauvage en interactive).
Rôle dans le projet (groupe)
Sur ce projet de groupe, je me suis principalement occupé de :
- Parsing : Build de l'ast qui servira a prioriser les operation utiliser dans l'execution
- Builtins : implémentation et intégration des commandes internes (ex.
cd,export,unset,echo,pwd,env,exit), avec un comportement cohérent côté environnement et codes de retour. - Testing & debug : création de cas de test (syntaxes, quotes, expansions, erreurs), reproduction de bugs, et triage pour identifier rapidement si le problème venait de mon périmètre (parsing/builtins) ou de celui de ma collègue (exec/FD/signaux, etc.).
Ce que ça m’a apporté
minishell m’a fait passer un cap “systèmes” : raisonner en termes de process graph, de flux (stdin/stdout), d’exit status, et d’edge cases réalistes. C’est aussi un excellent projet de collaboration : découpage des responsabilités, conventions d’équipe, et intégration de modules (parsing, env, exec, signals).
Bonus
Note : dès le début, notre AST était conçu pour supporter des extensions de grammaire. Même si toutes n’étaient pas exigées/activées dans la version rendue, la structure permettait d’ajouter proprement des opérateurs supplémentaires (ex.
&&,||, parenthèses/subshell).
- Extensions de grammaire (ex :
&&,||, parenthèses/subshell) - Amélioration des diagnostics (messages d’erreur plus proches de bash)
- Optimisations (moins de forks inutiles, meilleure gestion des builtins)
Lancement
./minishell
Lecture de ligne
- Prompt interactif via readline
- Historique de commandes
- EOF (
Ctrl-D) : quitte le shell
Builtins (implémentés)
echo(option-n)cdpwdexportunsetenvexit
Expansions
$VAR→ valeur de l’environnement$?→ code retour de la dernière commande-
Quotes :
-
'...': pas d’expansion "...": expansion$autorisée
Pipes & redirections
- Pipes :
cmd1 | cmd2 | cmd3 ... -
Redirections :
-
<input >output (truncate)>>output (append)<<heredoc (délimiteur)
Signaux (comportement attendu)
Ctrl-C: nouveau prompt propreCtrl-\: conforme au sujet (pas de quit brutal en interactif)
Pipeline global
- readline → récupère la ligne
- lexer/tokenizer → découpe en tokens (mots, opérateurs, quotes)
- parser → construit une représentation exploitable (AST)
- expander → applique
$VAR/$?selon les règles de quotes - executor → gère redirections, pipes, fork/exec, builtins
AST dès le départ
Notre architecture était pensée dès le début autour d’un AST afin de :
- séparer clairement parsing et exécution
- gérer naturellement la priorité des opérateurs (pipes, redirections, etc.)
- préparer les extensions de grammaire (ex.
&&,||, parenthèses/subshell) sans casser le code
Ton périmètre (groupe)
- Parsing / quoting : tokens, validation, construction de commandes/args
- Builtins : implémentation + intégration dans le pipeline
- Testing : création de cas limites + triage des bugs (parsing/builtins vs exec/FD/signaux)
Points critiques
- Les builtins comme
cd/export/unset/exitdoivent souvent s’exécuter dans le process du shell (sinon l’état ne persiste pas). - La gestion des fd (pipes/redirs) doit être propre : fermeture stricte pour éviter blocages.
readline+ signaux : maintenir un prompt propre, sans laisser le shell dans un état incohérent.