A UNIX shell implementation with command execution, pipeline handling, and variable expansion.
Minishell is a minimalistic shell implementation based on bash. It provides a command-line interface where users can execute commands, use pipes for command chaining, use redirections, and utilize environment variables, all with proper error handling and signal management.
- Run both built-in commands and external executables
- Accurate exit status reporting
echo
: Display text with-n
flag supportcd
: Change directory with path or relative navigationpwd
: Print working directoryexport
: Set or display environment variablesunset
: Remove environment variablesenv
: Display environment variablesexit
: Exit the shell with a specified status code
- Pipes (
|
): Connect command outputs to inputs, allowing complex command chains. - Redirections:
- Input redirection (
<
): Read input from a file. - Output redirection (
>
): Write output to a file, overwriting existing content. - Append output (
>>
): Append output to a file. - Heredoc (
<<
): Provide multi-line input to a command, with optional delimiter quoting to control expansion.
- Input redirection (
- Logical operators:
- AND (
&&
): Execute the next command only if the previous one succeeds. - OR (
||
): Execute the next command only if the previous one fails.
- AND (
- Environment Variable Expansion:
- Environment variable expansion.
- Special variable
$?
to display the exit status of the last command.
- Signal Handling:
Ctrl+C
(SIGINT): Interrupts the current foreground process or displays a new prompt if no process is running.Ctrl+D
(EOF): Exits the shell if the input line is empty.Ctrl+\
(SIGQUIT): Ignored by the shell to prevent accidental termination.
- Subshell Execution: Execute commands in a subshell environment using parentheses
(...)
. - Command History: Navigate through previously entered commands using arrow keys.
- Custom Memory Management: Utilizes a custom memory allocator for efficient resource handling and memory leak prevention.
- Robust Error Handling: Provides informative error messages for syntax errors, command not found, permission issues, etc.
The project is organized into the following main directories:
includes/
: Contains header files, includingminishell.h
and library headers.lib/
: Contains external libraries likelibft
.src/
: Contains the source code for Minishell, categorized into subdirectories:main/
: Main shell loop and initialization.ast/
: Abstract Syntax Tree construction and manipulation.environment/
: Environment variable management.execution/
: Command execution logic, including builtins and external commands.expansion/
: Variable and token expansion.heredoc/
: Heredoc processing.memory/
: Custom memory management utilities.scan/
: Input scanning and validation.signal_handeling/
: Signal handling logic.tokenization/
: Input string tokenization.utils/
: Utility functions used across the project.
Makefile
: Defines build rules for compiling the project.README.md
: This file.
# Clone the repository
git clone https://github.com/Yassir-aykhlf/minishell.git minishell
# Navigate to the project directory
cd minishell
# Compile the project
make
# Launch the shell
./minishell
Once running, you can use the shell like any standard UNIX shell:
# Simple command
echo Hello, World!
# Command with pipes
ls -la | grep "\.c$" | wc -l
# Environment variable usage
echo $HOME
# Redirections
echo test > file.txt
cat < file.txt
# Heredoc
cat << EOF
This is a multi-line
heredoc input
EOF
# Logical operators
cd /tmp && echo "Changed directory successfully"
cd /nonexistentdir || echo "Directory change failed"
The project implementation follows these key steps:
- Input Reading & History: Uses
readline
to read user input and manage command history. - Scanning: Validates the input for early syntax errors handling.
- Tokenization: Parses the input string into a list of tokens (commands, arguments, operators, redirections, etc). Each token is identified by its type and value, and a character mask is generated to handle quoting for expansion.
- Parsing (AST Construction): Builds an Abstract Syntax Tree (AST) data structure from the token list. The AST represents the command structure, including pipelines, logical operations, subshells, and redirections.
- Expansion: Traverses the AST to perform variable expansion (
$VAR
,$?
) and removes quotes. Field splitting is handled for unquoted expansions. - Heredoc Processing: Handles
<<
heredoc redirections by reading input until the delimiter is found, expanding variables within the heredoc. - Execution: Traverses the AST to execute commands.
- Handles built-in commands directly.
- Executes external commands by forking a child process and using the
execve
syscall. - Manages pipes and redirections by manipulating file descriptors.
- Implements logical operators (
&&
,||
) based on the exit status of commands. - Executes subshells in a separate child process.
- Signal Handling: Manages signals like SIGINT and SIGQUIT appropriately during command execution and while waiting for input.
- Memory Management: Employs a custom memory allocation wrapper to track allocations and facilitate easy cleanup, preventing memory leaks.
- GCC Compiler
- GNU Make
- Standard C Library
Contributions are very welcome! Please follow these steps:
- Fork the repository.
- Create a feature branch (
git checkout -b feature-name
). - Commit your changes (
git commit -m "Add some feature"
). - Push to the branch (
git push origin feature-name
). - Open a pull request.