Minishell
Minishell is a simple shell project for 42 school
Minishell subdivision
I. PARSING :
-
Lexer :
Lexing, tokenization, lexical analysis.
Converts a sequence of WORD into a sequence of tokens. -
Scanning :
Segments the input string into syntactic units called lexemes, into token classes.
-
Evaluating :
Converts lexemes into processed values.
-
Lexeme :
A "word". Sequence of WORD that matches a pattern for a token.
-
Token :
String with assigned meaning with a token name & token value.
-
Parser:
Puts tokens into a data structure called Command Table that will store the commands to be executed.
> INPUTS EXAMPLES :
echo bonjour > bonjour
echo -n bonjour > bonjour%
echo -n bonjour | echo cool > cool
echo "-n bonjour" > -n bonjour
echo 'bonjour > cas non prit en compte
echo "bonjour" > bonjour
echo bonjour > test\ 1 > echo "bonjour" inside file test 1
echo $HOME > echo $HOME variable value
echo '$HOME' > $HOME
echo "$HOME" > echo $HOME variable value
export a=10 > export variable a with value 10
ls >> abcd
ls <> abcd > error
ls | grep t
sort < abcd | grep t
other examples (not always up to date with the new subject)
- https://docs.google.com/spreadsheets/d/1BLU6C9S7aoCl01x74GiW7s4xpEWWJ1cPrMTcLwISruk/edit#gid=1627853444
- https://docs.google.com/spreadsheets/d/1fniV2dSRB5TaFGyX3O-iK0u61xR5jDdkFKYonKpilIc/edit#gid=0
- https://github.com/t0mm4rx/minishell_tests
SIGNALS:
ctrl + c
ctrl + d
ctrl + \
> INPUTS GRAMMAR :
[command](space)[arguments]
[command](space)[options][arguments]
[command](space)[options][arguments][operator][command](space)[options][arguments]
Operators
- pipe operator = |
- redirection operator = < << >> >
- (logical operator = && || )
- (list terminator = ; )
> PARSING EXAMPLE :
Take the following command :
echo -n bonjour | echo cool'$HOME top'"$HOME super" | echo $? > txt1
:
1. LEXER:
a. scanningRun through a scanning process that separates the words :
nb | word |
---|---|
1 | echo |
2 | -n |
3 | bonjour |
4 | | |
5 | echo |
6 | cool |
7 | '$HOME top' |
8 | "$HOME super" |
9 | | |
10 | echo |
11 | $? |
12 | > |
13 | txt1 |
:
b. evaluatingEvaluate the resulted lexemes into tokens :
token | token type |
---|---|
echo | WORD |
-n | WORD |
bonjour | WORD |
| | PIPE |
echo | WORD |
cool | WORD |
'$HOME top' | STRONG_WORD |
"$HOME super" | WEAK WORD |
| | PIPE |
echo | WORD |
$? | EXIT_STATUS |
> | REDIR_OUT |
txt1 | WORD |
:
2. SEARCHER- compares the "ALIAS" tokens against known aliases.
- compares the "WORD" tokens against known command names, builtins.
- searched around the environment PATH directories to find a match for it.
The order of comparing: - 1) aliases, - 2) builtins, - 3) environment path.
1) Aliases
When an alias is found, its values are stored in a structure like so :
typedef struct s_aliases { char *alias_name; char *real_name; } t_alias;
2) Builtins
When an builtin is found, its function pointer is stored in a structure like so :
typedef struct s_builtins { char *name; int (*func)(void); } t_builtins;
2) Environment path
In bash, if you input ENV, you will get in stdout a list of all those variables.
In order to access the environment, an external variable must be declared in the header :
extern char **environ;
Using loops, each directory is opened and stat() checks if the commandname is there. If positive, the directory is concatenated with a slash character and also with the user’s command, and the pointer is returned to be executed.
source : https://medium.com/swlh/tutorial-to-code-a-simple-shell-in-c-9405b2d3533e
:
3. PARSERParse the tokens into a data structure called the command table : The Command Table is an array of SimpleCommand structs.
command | option | arguments |
---|---|---|
echo | -n | bonjour |
echo | cool$HOME top/Usr/user42 super | |
echo | $? |
- execute "echo -n bonjour"
- the output is connected to the input of following command (PIPE)
- execute "echo cool$HOME top/Usr/user42 super"
- the output is connected to the input of following command (PIPE)
- execute "echo $?
- redirects output to file txt1
source : https://www.cs.purdue.edu/homes/grr/SystemsProgrammingBook/Book/Chapter5-WritingYourOwnShell.pdf
II. EXECUTOR
With the command table, and for each simple command, creates a new process.
-
Interpret: The shell reads commands from the command table and executes them.
-
Terminate: After its commands are executed, the shell executes any shutdown commands, frees up any memory, and terminates.
-
if system command, a new child will be created and then by using the execvp, execute the command, and wait until it is finished.
-
if built-in execute normally
-
for pipes, call each command into separate children using execvp.
- Declare an integer array of size 2 for storing file descriptors. File descriptor 0 is for reading and 1 is for writing.
- Open a pipe using the pipe() function.
- Create two children with fork
- Child 1->
- Here the output has to be taken into the pipe.
- Copy file descriptor 1 to stdout.
- Close file descriptor 0.
- Execute the first command using execvp()
- Child 2->
- Here the input has to be taken from the pipe.
- Copy file descriptor 0 to stdin.
- Close file descriptor 1.
- Execute the second command using execvp()
- Wait for the two children to finish in the parent.
ressource here : https://www.geeksforgeeks.org/making-linux-shell-c/
III. SUBSYSTEMS
- environment variables
- subshells
- history -> http://web.mit.edu/gnu/doc/html/rlman_2.html
- show prompt
- PATH variable, relative & absolute
- built-ins
- echo (-n)
- cd (path only)
- pwd
- export
- unset
- env
- exit
- redirection
- pipes
- signals with = ctrl + C, ctrl + D, ctrl + \
- $?
- ` (inhibits all interpretation of a sequence of WORD)
- `` (same, except for $)
- redirect STDIN and STDOUT
IV. CALL STACK
// size = ft_strlen(getcwd(cwd, sizeof(cwd))) +
// ft_strlen("\033[32m\u27A1\033[0m ") +
// ft_strlen(" \033[38;5;69m\u2613\033[0m ");
// data->prompt = (char *)malloc(sizeof(char) * (size + 1));
// strcat(data->prompt, "\033[32m\u27A1\033[0m ");
// strcat(data->prompt, getcwd(cwd, sizeof(cwd)));
// strcat(data->prompt, " \033[38;5;69m\u2613\033[0m ");