This project aims to recreate most of the bash shell.
- Status: finished
- Result: 125%
- Observations:
- It is compatible with Linux and Mac OS.
- It does not use
VT100
escape characters.
developed by: izenynn and 0xk0sta
git clone --recurse-submodules https://github.com/izenynn/minishell.git
Install readline library:
- On Debian based platforms, like Ubuntu:
sudo apt install libreadline-dev
- Platforms with
yum
, like SUSE:
yum install readline-devel
- For other platform please search for the package name on google, thx :)
- Install readline library:
brew install readline
Run make
(make rules: all
, clean
, fclean
and re
)
cd ./minishell && make
Execute the ./minishell
binary generated after running make
./minishell
To install minishell in your machine and be able to use it in any directory like any other command, run make install
(make sure you have the correct access rights).
sudo make install
To change the install directory specify the BIN_DIR
variable on make
sudo make install -D 'BIN_DIR=/usr/local/bin'
- Recreates most of the bash shell.
- support for config file
.minishrc
(like bash.bashrc
). - comments with
#
(NOTE:#
must be at the start of the line). - Pipes
|
works like in bash. - Redirections
<
,>
,<<
,>>
work like in bash. ;
,&&
and||
work like in bash.- Parenthesis:
(
and)
works with&&
,||
and;
for priorities. $?
works like in bash.- wildcards
*
and?
works for the current directory. - Handle signals:
Ctrl-C
,Ctrl-D
andCtrl-\
like in bash. - Enviroments variables.
- Arrow keys.
- History (command history).
- Auto-complete with tab key.
echo
cd
pwd
export
unset
env
exit
minishell is formed by 3 components:
-
Lexical analyzer: parse the input line into tokens.
-
Parser: parse tokens into an abstract syntax tree (ast).
-
Executor: execute the commands
To see how it works, go to src/main/handle_line.c
, uncomment the functions print_ast
and print_tokens
, in line 18 and 78, add the following lines to the handle_line
function and run make
again:
void handle_line(char *line, t_bool is_alloc)
{
t_lexer lex;
t_ast *ast;
int ret;
ast = NULL;
if (check_line(line, is_alloc) == 1)
return ;
ret = lexer_build(line, ft_strlen(line), &lex);
if (ret <= 0)
{
if (ret == 0 && g_sh.tokdel == FALSE)
write(STDERR_FILENO, "error: syntax error\n", 20);
free_line(line, is_alloc);
lexer_del(&lex);
return ;
}
free_line(line, is_alloc);
+ print_tokens(&lex);
if (lex.n_toks == 0 || parse(&lex, &ast))
{
free_all(&lex, ast);
return ;
}
+ print_ast(ast, 0); printf("------------------------------------\n");
if (exec_heredoc(ast) == 0)
exec_ast(ast);
free_all(&lex, ast);
}
Example:
minishell$ "invalid command" || (echo hello && echo world!)
------------------------------------
TOKENS:
n_tok: 10
type: -1, data: invalid command
type: 124, data: |
type: 124, data: |
type: 40, data: (
type: -1, data: echo
type: -1, data: hello
type: 38, data: &
type: 38, data: &
type: -1, data: echo
type: -1, data: world!
type: 41, data: )
type: 0, data:
------------------------------------
AST:
type: arg, data: world!
type: cmd, data: echo
type: &&
type: arg, data: hello
type: cmd, data: echo
type: ||
type: cmd, data: invalid command
------------------------------------
invalid command: command not found
hello
world!
minishell$
Grammar
<command line> : <and or> ';' <command line>
| <and or> ';'
| <and or>
;
<and or> : <job> '&&' <and or>
| <job> '||' <and or>
| <job>
| '(' <command line> ')' '&&' <and or>
| '(' <command line> ')' '||' <and or>
| '(' <command line> ')'
;
<job> : '(' <command> ')' '|' <job>
| <command> '|' <job>
| '(' <command> ')'
| <command>
;
<command> : <token list>
;
<token list> : [name] <token list>
| [token] <token list>
| [redir] <token list>
| (null)
;
<redir> : <redir in>
| <redir out>
;
<redir in> : '<<' [file]
| '<' [file]
;
<redir out> : '>>' [file]
| '>' [file]
;