Le projet MiniShell est une implémentation simplifiée d'un shell Unix. L'objectif est de reproduire le fonctionnement d'un interpréteur de commandes, en gérant :
- La lecture de l'entrée utilisateur.
- L'analyse lexicale et syntaxique de la ligne de commande.
- L'expansion des variables d'environnement.
- L'exécution des commandes, incluant les commandes internes (builtins) et externes.
- La gestion des redirections et des pipes.
- La gestion des signaux.
Je n'ai pu tester le projet que sur macOS (Arm), et debian (VM).
Le projet nécessite l'installation de la bibliothèque readline pour la lecture de l'entrée utilisateur.
MacOS:
brew install readlineDebian:
sudo apt-get install libreadline-dev-
Cloner le dépôt :
git clone [URL_DU_REPO] cd minishell -
Compiler le code source :
make
-
Exécuter le shell :
./minishell
Mon MiniShell fonctionne en plusieurs étapes principales :
- Boucle Principale :
- Affiche un prompt et lit la commande entrée par l'utilisateur (en utilisant
readline). - Ajoute la commande à l'historique (avec
add_history).
- Affiche un prompt et lit la commande entrée par l'utilisateur (en utilisant
- Analyse Lexicale (Lexer) :
- Transforme la ligne de commande en une liste de tokens.
- Identifie les mots, les opérateurs (pipes, redirections), et les espaces.
- Chaque token est stocké dans une structure
t_lexer.
- Analyse Syntaxique (Parser) :
- Prend la liste de tokens générée par le lexer.
- Organise les tokens en commandes.
- Identifie les redirections associées à chaque commande.
- Stock les infos dans la struct
t_command - Vérifie la syntaxe des commandes (gestion d'erreur).
- Expansion :
- Remplace les variables d'environnement par leurs valeurs (par exemple,
$HOME). - Gère les expansions de
?pour le code de retour de la dernière commande. - Supprime les guillemets non nécessaires .
- Remplace les variables d'environnement par leurs valeurs (par exemple,
- Exécution (Executor) :
- Traite chaque commande en fonction du type (builtin ou externe).
- Gère l'exécution de commandes en parallèle avec des pipes.
- Exécute les commandes internes en utilisant la table de builtins.
- Gère les redirections de flux d'entrée et de sortie.
- Gère la création des processus enfant (fork), l'execution des commandes avec execve et l'attente des processus enfants (waitpid)
- Gère l'heredoc (gestion de l'entrée ici).
- Builtins :
- Implémente des commandes internes comme
echo,cd,pwd,export,unset,envetexit. - Ces commandes sont exécutées directement par le shell sans créer de nouveau processus.
- Implémente des commandes internes comme
- Gestion des Signaux :
- Le shell ignore SIGQUIT.
- Le shell gère les signaux SIGINT (Ctrl+C) pendant l'execution ou en heredoc.
Le programme est conçu pour fonctionner avec les commandes de base de UNIX (avec leur options), les pipes et redirections basiques.
On peut remonter dans l'historique des commandes avec les flèches haut et bas, et utiliser les flèches gauche et droite pour se déplacer dans la ligne de commande. Ctrl+C permet d'envoyer un signal SIGINT au processus en cours. Exit/ctrl+D permet de quitter le shell.
Le shell ne permet pas de copier coller plusieurs lignes de commandes en même temps.
Quelques exemples de commandes à essayer :
-
Commandes de base :
ls -l echo "Hello, World!" pwd cd pwd
-
Commandes Environnement :
env echo $HOME echo $PATH export MY_VAR=42 /usr/bin/env | grep MY_VAR unset MY_VAR /usr/bin/env | grep MY_VAR
-
Commandes avec Pipes :
ls -l | grep "nicolasroy" ls -l | grep "nicolasroy" | wc -l
-
Commandes avec Redirections :
ls -l > ls.txt cat ls.txt echo "Hello, World!" > hello.txt cat hello.txt echo "Bonjour" >> hello.txt cat hello.txt
-
Commandes avec Heredoc :
cat << EOF Hello, World! EOF
Sur macOS, la vérification des fuites de mémoire a été effectuée à l'aide des outils suivants :
- Sanitizer (ASan) :
Compilation avec l'
Address Sanitizer(-fsanitize=address). - Leaks :
La commande
leaks -atExit -- ./minishell
-
t_lexer:- Représente un token unique issu de l'analyse lexicale.
- Champs :
char *str: La chaîne de caractères du token.t_tokens token: Le type de token (par exemple,PIPE,GREAT,LESS).int i: index du tokenstruct s_lexer *next: Pointeur vers le token suivant dans la liste.struct s_lexer *prev: Pointeur vers le token précédent dans la liste.
-
t_utility:- Structure centrale contenant l'état global du shell et les outils nécessaires.
- Champs :
char *args: La ligne de commande brute entrée par l'utilisateur.char **paths: Un tableau de chaînes contenant les chemins où chercher les exécutables.char **envp: L'environnement du shell.struct s_simple_cmds *command: La liste des commandes à exécuter après le parser.t_lexer *lexer_list: La liste chainé contenant tous les tokens.char *pwd: Le chemin du repertoire actuelchar *old_pwd: Le chemin du repertoire précédentint pipes: Nombre de pipesint *pid: Un tableau d'identifiants de processus pour la gestion des pipesbool heredoc: flag pour indiquer qu'un heredoc est en cours d'executionbool reset: flag pour indiquer si le shell a été réinitialiser
-
t_simple_cmds:- Représente une commande simple, potentiellement incluse dans un pipeline.
- Champs :
char **str: Un tableau de chaînes représentant les arguments de la commande.int (*builtin)(t_utility *, struct s_simple_cmds *): Un pointeur vers la fonction builtin (si la commande est interne).int redirect_count: Nombre de redirectionschar *file_name: Nom de fichier (pour les herdoc)t_lexer *redirections: La liste chainé des redirection associés à la commandestruct s_simple_cmds *next: Pointeur vers la commande suivante dans un pipeline.struct s_simple_cmds *prev: Pointeur vers la commande précédente dans un pipeline.