Simple Shell is a custom command-line shell that I implemented in C, showcasing my understanding of process management, signals, and Unix system programming. This shell supports executing commands in both foreground and background modes, includes several built-in commands, and maintains a history of the most recent 10 commands.
While the project’s specifications were based on SFU CMPT 201 Assignment 8, I designed and implemented the full shell functionality, including process handling, signal management, and command parsing.
- Runs user commands in foreground or background depending on the presence of
&. - Implements proper error handling for invalid commands or system call failures.
- Cleans up zombie processes for background commands.
exit: Exits the shell.pwd: Prints the current working directory.cd: Changes the working directory with support for:- No argument → switches to home directory
~→ home directory shortcut-→ previous directory
help: Lists internal commands or provides help for a specific command.
- Maintains the 10 most recent commands with indices.
history: Displays command history in descending order.!!: Re-runs the last command.!n: Re-runs the command with indexn.- Tracks background commands in history as well.
- Handles
SIGINT(Ctrl-C) gracefully, without terminating the shell. - Displays help information when
SIGINTis received.
simple_shell/
├── CMakeLists.txt # Build configuration
├── include/ # Header files
│ └── shell.h
├── src/ # Source code files
│ ├── main.c
│ ├── commands.c
│ ├── history.c
│ └── utils.c
└── gtest/ # Test cases (Google Test)
Requirements: clang, clang++, CMake
# Set compilers
export CC=$(which clang)
export CXX=$(which clang++)
# Build the project
cmake -S . -B build
cmake --build build
# Run the shell
./build/shell- Foreground execution:
/home/user$ ls -la- Background execution:
/home/user$ sleep 10 &- Change directory:
/home/user$ cd ~/Documents- Display history:
/home/user$ history- Re-run a previous command:
/home/user$ !3- Implemented using
fork(),execvp(), andwaitpid()for robust process management. - Uses
read()andwrite()for safe input/output handling with signals. - Handles zombie processes and ensures the shell remains responsive for new commands.
- Built-in commands are executed without spawning new processes.
- Support for input/output redirection (
>). - Support for command pipelines (
|). - Extendable history storage beyond the last 10 commands.
The project’s requirements and grading specifications were adapted from SFU CMPT 201 Assignment 8. All code, design decisions, and implementation were developed independently.