A lightweight Unix shell implementation written in C, featuring pipes, I/O redirection, background jobs, and command chaining.
MiniShell reproduces the core behavior of a Unix shell. It parses and executes command lines with support for:
- Pipes (single and chained):
ls -la | grep .c | wc -l - Background execution (
&):sleep 10 & - Stdout redirection (
>):echo "hello" > output.txt - Command chaining (
;):mkdir test ; cd test ; pwd - Built-in commands:
cd,pwd,exit,jobs - Signal handling: proper
SIGCHLDmanagement for background processes
Prerequisites: GCC, Make, Linux
# Build
make
# Run
./bin/minishell
# Clean object files
make clean
# Full clean (objects + binary)
make aclean
# Rebuild from scratch
make rebuild# Simple commands
ls -la
echo "Hello, World!"
# Pipes
cat /etc/hosts | grep localhost
ls -la | grep .c | sort | head -5
# Background execution
sleep 30 &
jobs # List background jobs
# Output redirection
ps aux > processes.txt
# Command chaining
ls ; echo "---" ; pwd
compile.sh & echo "Building in background..."minishell/
├── src/
│ ├── main.c # Entry point — main REPL loop
│ ├── shell.c # Parser and command execution engine
│ ├── command.c # Command data structure and background job management
│ ├── terminal.c # User input handling and prompt display
│ └── utils.c # String utility functions
├── inc/
│ ├── shell.h
│ ├── command.h
│ ├── terminal.h
│ └── utils.h
├── makefile
├── LICENSE
└── README.md
The shell runs a Read-Eval-Print Loop (REPL) in main.c:
┌─────────────────────────────────────────────────┐
│ 1. Display prompt (user@host:~/path$) │
│ 2. Read user input │
│ 3. Validate syntax (reject invalid sequences) │
│ 4. Report completed background jobs │
│ 5. Parse input into Command structures │
│ 6. Execute each command │
│ └─→ Loop back to 1 │
└─────────────────────────────────────────────────┘
The parser performs three-level tokenization:
- Command level — Split by
;and&(marks background flag) - Pipe level — Split by
|and>(marks file redirection) - Argument level — Split by whitespace
Each command is represented by a Command struct:
typedef struct Command {
char*** args; // Arguments for each sub-command
int n_pipe; // Number of pipe segments
int* n_args; // Argument count per segment
int is_file_output; // Stdout redirected to file
int is_background; // Run in background
pid_t pid; // Associated process ID
int command_id; // Job ID (displayed in brackets)
CommandState state; // RUNNING, DONE, EXIT_126, EXIT_127
struct Command *next; // Linked list pointer (for background jobs)
} Command;- Built-in commands are executed directly in the shell process (no fork)
- External commands use
fork()+execvp() - Pipes are implemented using
pipe()anddup2()to chain stdin/stdout between processes - Background jobs are tracked in a global linked list and monitored via
SIGCHLD
- No support for
stderrredirection (2>) or append mode (>>) - No wildcard/glob expansion (
*,?) - No environment variable expansion (
$VAR) - No quotes handling for arguments with spaces
- Single-line input only (no multi-line or heredoc support)
This project is licensed under the MIT License — see the LICENSE file for details.
Jules Guignard