A shell is a command-line interface that enables users to interact with the operating system by typing commands. It interprets and executes these commands, allowing for efficient task execution, automation, and system management, particularly in UNIX-like systems.
This project implements a custom shell, providing core functionalities such as input scanning, command parsing, and process execution. It’s designed as a simplified version of shells like Bash, offering valuable insights into shell operations, command execution, and process management.
The architecture of the shell comprises several key components that work together to parse and execute commands.
The Lexer (or Lexical Analyzer) reads user input and breaks it down into tokens for the parser.
- Input Scanning: Reads user input and processes it character by character.
- Function:
get_next_char()– Retrieves the next character from the input stream.
- Function:
- Tokenization: Splits input into tokens representing commands, arguments, operators, or special characters.
- Function:
tokenize()– Processes the input to return distinct tokens.
- Function:
echo "Hello, World!" > output.txtTokens generated:
- Command:
echo - String Argument:
"Hello, World!" - Redirection Operator:
> - File Argument:
output.txt
The Parser transforms the tokens from the lexer into a structured representation, typically an Abstract Syntax Tree (AST).
- parse_simple_command – Parses a simple shell command.
- new_node – Creates nodes in the AST.
- set_node_val_str – Assigns a string value to a node.
- add_child – Adds child nodes to build the AST.
- free_node_tree – Recursively frees nodes for cleanup.
The Executor converts parsed commands into system calls that interface with the operating system.
- Command Execution: Executes external commands using
fork()andexecvp(). - Built-in Commands: Detects and executes built-in commands (e.g.,
cd,exit). - Process Management: Uses
fork()andwaitpid()to manage processes. - Input/Output Redirection: Redirects streams using
dup2. - Pipes: Sets up and manages data flow between commands connected by pipes.
- Background Execution: Supports background processes (commands ending with
&).
The Symbol Table manages variables and functions within the shell.
- Symbol Table Entry (
symtab_entry_s): Represents a symbol, such as a variable or function. - Symbol Table (
symtab_s): A scope that contains multiple symbols. - Symbol Table Stack (
symtab_stack_s): Manages multiple symbol tables, supporting local and global scopes.
Screenshots of the shell (compiled on void linux).

To compile and run the shell, use the following commands. Ensure you have gcc installed.
- Clone the repository to your local machine.
- Navigate to the project directory.
- Compile the code using the following
gcccommand:
gcc -o shell \
builtins/builtins.c builtins/dump.c \
core/main.c core/prompt.c \
executor/executor.c \
input/input_stream.c \
lexer/lexer.c \
parser/parser.c parser/node.c \
symbol_table/symbol_table.c
core/initsh.c
After compilation, run the shell with:
./shellYou can now start entering commands in the shell interface






