42's project, minimal shell
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Fabien Stadelwieser e1eed84ab9
Readme
4 months ago
inc pars: ' and \ with $ expantion work 1 year ago
lib/libft lib: norm fix for operator 1 year ago
src pars: separator can now be escapted and quoted 1 year ago
.function_whitelist.txt all: Structure prototyped 1 year ago
.gitignore build: seperate obj files for debug 1 year ago
Makefile build: lib makefile addapted & lib pedantic 1 year ago
README.md Readme 4 months ago
author all: Structure prototyped 1 year ago
bonuslist.txt pars: separator can now be escapted and quoted 1 year ago

README.md

Minishell

A simple posix shell.

./minishell
$> # type you command here
$> ls
file1 file2
$> ls nofile
$> echo $?
1
$> cd ..
$> echo $TEST
$> setenv $TEST value
$> echo $TEST
value
$> exit

A simple workshop for what's to come in 21sh and 42sh.

Install

Compatible Linux and MacOS

git clone ssh://git@git.42l.fr:42084/Fabien/minishell.git
cd minishell
make

How it works

Initalization

Normally almost each shell has a script is loaded from a file named : ~/.<shell_name>rc, like .zshrc or .bashrc.

It's not part of this project, and so are the arguments.

Input

In this project the input is fairly simple. You use a function from another project, the infamous get_next_line, 42's getline.

You need a solid get_next_line, many bugs can come from a bad one that have not been written with interactive input in mind.

So you loop over the input (fd -> 0 sometime called stdin). And for each line you do a strsplit on each line, where you split on <space>.

The first "word" is the command for this project, the rest is the argument, you just keep them for later.

Command

If the command have a '/' in it the path is checked, if correct you skip the next step.

Otherwise, you search in the env for a variable called $PATH.

$> echo $PATH
/bin:/usr/bin:/home/user/.bin

Then for each command search in each directory listed in $PATH.

For ls :

  • No ls in /bin/ls
  • ls is in /usr/bin/ls
  • /home/user/.bin is not checked because ls have already been found

When the executable has been found, a new process is created with fork, the command is run with its argument thanks to execve and the main process wait for its child to finish with wait.

man fork
man execve
man wait

Builtin

Some command cannot have the desired result in a child process.

One example of this is exiting the shell or modifying the env. Each of those would only affect the child and then return to the parent leaving nothing.

For those cases, shells have something called "builtins" that are not run in the main process.

In our case they are :

  • exit
  • setenv
  • unsetenv
  • cd

These are a builtin for the sake of the exercise, but don't need to be.

  • echo
  • env

Builtin are checked before the command, so if you want to exec /usr/bin/env you need to type /usr/bin/env and simply env for the builtin. man env give you informations about the executable whereas help env, give you info about the builtins. (No help in our case)

Don't forget to store the return value in $? and return this when the shell exit.

Bonus

  • Non-interactive input (ei: pipe as input)
  • Simple and double quotes [' and "]
  • Backslash [\]
  • Multiline input
  • Signal management (<Ctrl + C> and <Ctrl + \>)
  • Proper signal message and "core dumped"
  • Run on Linux
  • tcsh compatible on the feature-set

Credit

Student project for School 42.

Realized by myself in about a week.

Final Grade: 120/125