Aussi mignon qu’un vrai shell
Start
make && ./minishell
Liste non exaustive des Failed tests
Sujet -> EN
Scale de correction -> EN
L'objectif du projet est de creer notre propre shell.
Le shell c'est en quelque sorte l'interface utilisaeur d'un systeme. Il permet à l'utilisateur de communiquer avec le système d’exploitation par l'intermédiaire de commandes. L'utilisateur rentre des commandes dans le terminal et grâce à l’interpréteur de commande (tel que bash ou zsh qui sont des shells), les commandes entrées sont exécutées.
- Le sujet de minishell a eu plusieurs mises a jour. Ici nous ne faisons pas les termcaps (utilisation de
readline
,rl_clear_history
, ...). - Nous avons du adapter le code pour utiliser qu'une seule variable globale.
- Nous interprétons les caractères spéciaux
\
et;
, mais dans la maj du sujet on n'est pas obligés de les gérer.
On va créer une liste chaînée à partir de l'environnement contenant à chaque maillon le nom de la commande et ses arguments.
typedef struct s_token
{
char *word;
int type;
struct s_token *prev;
struct s_token *next;
} t_token;
typedef struct s_cmd
{
char *cmd;
char *tmp;
t_token *args;
t_list *env;
int type;
int in;
int out;
struct s_cmd *prev;
struct s_cmd *next;
} t_cmd;
Le but va etre de trier notre input par type. On split selon les quotes et les opérateurs rencontrés. On construit un tableau de structure avec comme attribut le caractère séparateur ainsi que la chaîne contenue entre les deux délimiteurs.
Chaque type a une valeur (0: point virgule, 1: pipe, 2: redirection, 3: variable d'environnement, 4: newline, 5: texte, 6: exit status).
$ Ceci est un beau $parsing ; Avec des >> commandes | et des arguments
[5] [Ceci est un beau]
[3] [$parsing]
[0] [; Avec des]
[2] [>> commandes]
[1] [| et des arguments]
Pour mieux s'y retrouver dans les types, on fait un enum. cela permet en quelque sorte de donner un nom a des int. Par defaut la premiere valeur (ici POINT_V
) vaut 0 et les suivantes +1. Il est donc simple de rajouter un type.
typedef enum e_type{
POINT_V, // = 0
PIPE, // = 1
REDIR, // = 2
ENV, // = 3
NEWL, // = 4
TXT, // = 5
EXIT_STATUS // = 6
} t_type;
En savoir plus sur la tokenisation et l'AST -> @LucieLeBriquer
-
env
permet d'afficher toutes les variables d'environnement. -
export
permet de set des variables d'environnement (deja existante ou non). -
unset
permet de supprimer des variables. Unset peut supprimer plusieurs variables d'environement simultannement si on lui envoi plusieurs arguments. Si on unset une variable qui n'est pas présente dans les variables on n'a pas de message d'erreur et echo $? renvoi 0
Exemple | export |
env |
Commentaire |
---|---|---|---|
Sans argument | print la liste de toutes les variables d’environnement dans l’ordre ascii. Sous la forme : declare -x NAME="VALUE" ou declare -x NAME |
print la liste des variables d’environnement dans un ordre random. Sous la forme : NAME=VALUE |
|
Sans = export maman |
declare -x maman | la variable n'apparait pas | |
Avec un = et rien apresexport maman= |
declare -x maman="" | maman= | |
export HOME= |
declare -x HOME="" | HOME= | si on fait cd apres, on ne doit pas avoir le message "HOME not set", il ne se passe rienecho $? renvoi 0 |
cas classique export lol=mdr |
declare -x lol="mdr" | lol=mdr | |
Le export +=export a=b ; export a+=b ; export a+=b |
declare -x a="bbb" | a=bbb | On ajoute le nouveau contenu au contenu existant de la variable |
plusieurs argumentsexport var= omg |
declare -x omg declare -x var="" | var= |
➜ export y=ec
➜ $yho a
en fait si tu tape dans bash simplement
$something
mais la variable something
n'est pas set, il ne se passe rien
donc si je tape $something a
on doit rien faire pour le premier argument et a
est interprete comme si on avait une commande (ici c'est commande not found)
➜ export var=a
➜ unset var
➜ export $var=test
il faut un message d'erreur : bash: export: `=test': not a valid identifier
Creér un fork.
int pid;
pid = fork();
if (pid < 0)
/* Error forking */
if (pid == 0)
/* Child process */
else
/* Parent process */
L'utilisateur peut rentrer le nom de la commande (ex : ls
) ou le path (ex: /bin/ls
).
si c'est juste le nom aui est entré il faut récupérer le path de la commande avec la fonction lstat
.
la fonction execve
prend en paramètre le path ou le nom du commande a executer, un tableau d'arguments, et l'environement (ici on met NULL
).
Numéro de code de sortie | Sens | Exemple | Commentaire |
---|---|---|---|
1 |
Catchall pour les erreurs générales | let "var1 = 1/0" |
Erreurs diverses, telles que "diviser par zéro" et autres opérations non autorisées |
2 |
Mauvaise utilisation des commandes intégrées du shell (selon la documentation Bash) | exit 3.14159 |
Mot - clé ou commande manquant , ou problème d'autorisation (et code de retour diff en cas d'échec de la comparaison de fichiers binaires ) |
126 |
La commande invoquée ne peut pas s'exécuter | /dev/null |
Le problème d'autorisation ou la commande n'est pas un exécutable |
127 |
command not found |
fdp |
Problème possible avec $PATH ou une faute de frappe |
128 |
Argument invalide pour quitter | exit 3.14159 |
exit ne prend que des arguments entiers compris entre 0 et 255 (voir la première note de bas de page) |
128+n |
Signal d'erreur fatale "n" | kill -9 $PPID of script |
$? renvoie 137 (128 + 9) |
130 |
Script terminé par Control-C | Ctl-C |
Control-C est le signal d'erreur fatale 2 , (130 = 128 + 2, voir ci-dessus) |
255* |
État de sortie hors de portée | exit -1 |
exit ne prend que des arguments entiers compris entre 0 et 255 |
Readme 😏
Git: pense-bête