This project aims to implement a shell in C Language
that mimics the Bash shell.
Some features :
- Parses command pipeline
- Executes a command pipeline
- Handles special characters
- Handles environment variables
- Handles single and double quotes
''
""
- Handles signals
- Redirection
>
<
>>
- Heredocument
<<
- handles pipes
|
- Builtin commands
echo
,cd
,pwd
...
$> make docker
$> git clone 'git@github.com:jaguar-ks/MINI_SHELL.git'
$> cd MINI_SHELL
# ***`MacOS`*** : make sure you have the ***`readline`*** library installed (https://github.com/kube/42homebrew)
$> brew install readline
# ***`Debian`*** : make sure you have the ***`libreadline-dev && pkg-config`*** packages installed
$> apt update && apt install -y pkg-config
# Now you can compile and run the binary
$> make && ./minishell
To parse the input prompt line, we first split the string by spaces outside of any quotes.
Subsequently, we iterate over the resulting list and further split any node that contains a redirection character, such as [<
, >
, >>
, <<
, |
].
The process will result in a structure resembling the following:
In this phase, we identify the pipe |
and the redirections [<
, >
, >>
, <<
].
- If we encounter one of [
<
,>
,>>
], it signifies that the subsequent node will be a file. - If we encounter
<<
, it indicates that the next node is a delimiter for the heredoc. - If we encounter
|
, it signifies that the next set of nodes, up to the next|
or the end of the list, forms a separate command.
We then split the list at the |
node if it exists; otherwise, we handle it as a single command.
Note: If the first or the last node is
|
, or if we find a|
immediately following a redirection [<
,>
,>>
,<<
], it results in a syntax error.
Next, we identify the command to be executed. This step is straightforward because we have already determined the positions of the pipe and the redirections.
- To locate the command, we skip any node that has already been identified.
- The first unidentified node encountered is deemed to hold our command.
Finally, we identify the flags and arguments.
- After the command node, any unidentified node starting with
-
is considered a flag. - Any other unidentified node is considered an argument.
Note: If a flag is found after an argument, it constitutes an error.
The execution part of the minishell project handles the running of parsed commands. It deals with executing built-in commands, managing child processes, handling file redirections and pipes, and ensuring proper cleanup of file descriptors. Below is an overview of the main components and their roles.
- _execute_command: Executes a single command.
- Checks if the command is a built-in, and if so, executes it.
- If not, finds the command's path and uses
execve
to run it. - Handles errors if the command is not found.
- wait_childs: Waits for all child processes to finish execution.
- Checks for segmentation faults and handles them accordingly.
- Waits for all child processes and returns the last exit status.
- init_var: Initializes file descriptor variables for standard input and output.
- Sets default values for input and output file descriptors and resets error flags.
- _execute_in_child: Prepares and executes a command in a child process.
- Sets up redirections using
dup2
. - Closes unnecessary file descriptors.
- Executes the command.
- Sets up redirections using
- execute_pipeline: Manages the execution of a series of commands connected by pipes.
- Initializes variables and opens necessary pipes and redirections.
- Executes each command in the pipeline.
- Waits for all child processes to finish.
-
_handle_redirections: Opens files for input and output redirections.
- Handles different types of redirections (
<
,>
,>>
) and stores the file descriptors. - Manages error cases for file opening.
- Handles different types of redirections (
-
open_redirections: Processes all redirections for a command pipeline.
- Iterates through redirection tokens and applies them using
_handle_redirections
.
- Iterates through redirection tokens and applies them using
-
find_cmd: Searches for the executable of a given command in the provided paths.
- Checks for direct paths or searches within system paths.
- Returns the full path if found, otherwise returns
NULL
.
-
get_cmd_path: Retrieves the system
PATH
environment variable and uses it to find the command's executable.- Splits the
PATH
and usesfind_cmd
to locate the executable.
- Splits the
- open_pipes: Sets up pipes between commands in a pipeline.
- Creates pipes and assigns the input and output file descriptors accordingly.
- Ensures proper connection of command outputs to subsequent command inputs.
- close_file_descriptors: Closes all open file descriptors except standard input, output, and error.
- Ensures cleanup of file descriptors after command execution.
- execute_all_commands: Executes all commands in a given pipeline.
- Forks processes for each command.
- Executes commands in child processes and handles errors.
- Waits for the last child process and updates the exit status.
- Initialization:
- Initialize file descriptors and error flags.
- Redirection and Pipe Setup:
- Open necessary redirections and pipes for the command pipeline.
- Command Execution:
- Execute each command in the pipeline, managing child processes and handling errors.
- Cleanup:
- Close all file descriptors and wait for child processes to complete.
This process ensures that commands are executed correctly, handling built-ins, external commands, redirections, and pipelines with proper resource management.
This project was developed and validated by 0xJ4GU4R
and LeakedByteBuster
. With a final mark of: