Skip to content

Cartoone9/minishell

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Project score

minishell

This is my Minishell project: a small Bash-like shell written in C as part of the 42 common core. It parses and executes user commands, handles pipes and redirections, and manages signals and child processes with proper system calls.
We had to rebuild key parts of a shell from scratch: quoting, environment variables, file descriptors, fork/exec logic, and more.
It was a deep dive into Unix internals and low-level system programming. Everything from process creation to memory management was handled manually, using a range of standard and POSIX libraries (such as unistd.h, fcntl.h, signal.h, and readline.h) to interact with the system. Overall, this project gave me a much clearer understanding of what a shell actually does under the hood.

Table of Contents

Usage

To compile the program, navigate to the project root and run:

make
# or
make bonus

Minishell compiling

Then you can start the program like this:

./minishell

Example

Minishell demo

Features

In the following examples I will try to present most of the features supported, but not everything is shown here.
The minishell project is covering a lot of ground, and the best way to check all of its features would be to use the program directly.

Basic

This example shows a basic echo command with a redirection to a file output.

minishell_basic

Quoting forces a literal interpretation of special characters such as | or >.

minishell_double_quote
Empty

This example is to test empty commands. A simple line return, nothing quoted, and space quoted.

minishell_empty
Redirections

The next example is showing support of the multiple input redirections in random order, before and after the main command.
As you can see, only the last file is used for the redirection while the previous files are created if they don't exist.

minishell_redir

Same for multiple output redirections. The redirections work without spaces or with quotes.

minishell_redir_2

If no command is used, the file is emptied just like Bash would do.

minishell_redir_3
Heredocs

This section demonstrates heredoc support. You can combine heredocs just as you can with simple redirections.
If a pipe ends the command line, heredocs are resolved first, and then the program displays the appropriate prompt for the remaining pipe.

minishell_heredoc_pipe
Pipes

This example demonstrates a simple command using pipes.

minishell_pipe_1

This example shows heredoc behavior with pipes. As long as the last command ends with a pipe, a new prompt will open.
Once a command does not end with a pipe, the multiple commands are merged into a single one.

minishell_pipe_end
Echo

This first example will show the basic behavior of echo when used with multiple quotes mixed.

minishell_echo_1

The echo builtin is also supporting the use of the -n flag.

minishell_echo_n

We can go a little further by exporting a variable containing spaces in our environment.
Then depending on the quotes used, the expansion will vary, either splitting the variable or not.

minishell_echo_export
Cd

The following examples will showcase the cd behavior.
If no argument is passed, cd will use HOME as long as it exists.

minishell_cd_1

If HOME is not set, the program will return an error.

minishell_cd_2

You can export a variable HOME in order to set it to the desired path.

minishell_cd_3

Here we can see it fail on a locked directory, and a missing directory.

minishell_cd_4

The following image is showing the cd command used with .. and . in accordance to the subject.
We use pwd to check that we are in the correct directory, even though the current working directory is updated directly in the prompt.

minishell_cd_dot
Exit

If a value contained in a long long is passed to the exit command, it will be used as the returned value.

minishell_exit_1

That only works when using a numeric value.

minishell_exit_5

And with a single argument.

minishell_exit_6

If no value is passed to the exit command, then the last command status is returned.
Here we test this by first using ctrl + c to set the status to 130, then we exit. The returned value is indeed 130.

minishell_exit_7
Errors

First is a simple example using an unknown command.

minishell_unknown

Here I used the ls command to show the possible file errors and the ways the program is dealing with them.
As you can see, the correct error messages and returned values are used, even when using a redirection or not.

minishell_full_perm
Path

This example is used to show that removing the PATH will stop relative commands from executing, but absolute commands should still work.
Adding a PATH again should allow for the execution of the commands found in that PATH.

minishell_path
Wildcards

Finally we can see the wildcard support in the following examples. First we check that we can get all the files expanded.
Then only the folders, only the hidden files, only the hidden folders, only the hidden folders containing it at the end, and finally only the hidden folders containing i followed by a t at the end.

minishell_wildcard

We also can check the wildcard behavior when used with redirections, or quotes.

minishell_wildcard_2

Note on Project State

All projects from my 42 cursus are preserved in their state immediately following their final evaluation. While they may contain mistakes or stylistic errors, I've chosen not to alter them. This approach provides a clear and authentic timeline of my progress and learning journey as a programmer.

Known Issues & Fix Suggestions

Ctrl + C in a blocking command, like cat, doesn't return before a new prompt.
bug_ctrlc_minishell

One easy way to fix this would be to add this function ft_handle_wait_signal():

void	ft_handle_wait_sigint(int signal)
{
	(void)signal;
	write(1, "\n", 1);
	rl_replace_line("", 0);
	rl_on_new_line();
}

Then modify ft_wait_signals() to use the new function we just made:

void	ft_wait_signals(void)
{
	struct sigaction	sa;
	struct sigaction	sa_quit;

- 	sa.sa_handler = SIG_IGN;
+	sa.sa_handler = ft_handle_wait_sigint;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGINT, &sa, NULL);
	sa_quit.sa_handler = SIG_IGN;
	sigemptyset(&sa_quit.sa_mask);
	sa_quit.sa_flags = 0;
	sigaction(SIGQUIT, &sa_quit, NULL);
}

Killing a program like vim from inside minishell can leave the terminal in a messy or unusable state (broken prompt). This happens because such programs modify the terminal's settings (termios), and when they’re killed abruptly, those settings aren’t reset properly.
bug_prompt_minishell

This can be fixed by saving the current terminal attributes using tcgetattr() before launching the command, and restoring them afterward using tcsetattr().
While this is a known edge case, it's quite niche for this project’s scope so I chose not to handle it further.

Credits

This project was developed in collaboration with another student, who contributed to the implementation of built-in commands, signal handling, and provided valuable debugging support.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors