A custom Unix-like shell implementation in C that provides a comprehensive command-line interface with support for process management, I/O redirection, piping, job control, and custom built-in commands.
- Overview
- Features
- Prerequisites
- Installation
- Running the Shell
- Built-in Commands
- Advanced Features
- Project Structure
- Testing
- Implementation Details
- Signal Handling
- Author
C-Shell is a Unix-like shell implemented in C that mimics the functionality of popular shells like bash and zsh. It features a custom prompt, command parsing, process execution, job control, and signal handling. The shell is built with modularity in mind, separating concerns across multiple source files for maintainability and scalability.
- Custom Shell Prompt: Displays username, hostname, and current working directory
- Command Execution: Execute system commands and custom built-in commands
- Process Management: Support for both foreground and background process execution
- I/O Redirection: Input (
<), output (>), and append (>>) redirection - Piping: Chain multiple commands using pipes (
|) - Command Chaining: Support for sequential (
;) and conditional (&&) command execution - Command History: Persistent command logging with execution replay
- Job Control: Background job management with process tracking
- Signal Handling: Graceful handling of Ctrl+C, Ctrl+Z, and child process termination
hop- Enhanced directory navigationreveal- Advanced directory listing with flagslog- Command history managementactivities- Display all background processesping- Send signals to processesfg- Bring background jobs to foregroundbg- Resume stopped jobs in background
Before building and running C-Shell, ensure you have the following installed:
- GCC Compiler (version supporting C99 standard)
- Make utility
- POSIX-compliant system (Linux, macOS, or Unix-like OS)
- Python 3 (for running tests)
- pip (for installing test dependencies)
- Operating System: Linux/Unix/macOS
- Memory: Minimum 256 MB RAM
- Disk Space: ~10 MB for compilation and execution
-
Clone the repository:
git clone https://github.com/TECHIE-TITAN/C-Shell.git cd C-Shell -
Compile the shell:
make all
This will:
- Create a
build/directory for object files - Compile all source files from
src/directory - Generate the executable
shell.out
- Create a
-
Verify compilation:
ls -l shell.out
You should see the
shell.outexecutable file.
./shell.outOr use the make target:
make run<username@hostname:current_directory>
Example:
<vansh@ubuntu:~/C-Shell>
The tilde (~) represents the home directory of the shell session.
- Type
exitor pressCtrl+D(EOF) - The shell will terminate all child processes before exiting
Navigate between directories with enhanced features.
Syntax:
hop [path]Examples:
hop # Go to home directory
hop ~ # Go to home directory
hop . # Stay in current directory
hop .. # Go to parent directory
hop - # Go to previous directory
hop /path/to/dir # Go to specific directoryFeatures:
- Maintains previous directory for quick switching
- Supports absolute and relative paths
- Handles special symbols (
~,.,..,-)
Display directory contents with optional flags.
Syntax:
reveal [flags] [path]Flags:
-a: Show hidden files (files starting with.)-l: Display in long format (one file per line)
Examples:
reveal # List current directory
reveal -a # Show hidden files
reveal -l # Long format listing
reveal -al ~ # Show all files in home directory (long format)
reveal /etc # List specific directoryFeatures:
- Lexicographically sorted output
- Support for multiple flags
- Works with special directory symbols
Manage and replay command history.
Syntax:
log # Display command history
log purge # Clear all command history
log execute <index> # Execute command at indexExamples:
log # Show last 15 commands
log execute 3 # Execute the 3rd command from history
log purge # Clear all historyFeatures:
- Stores up to 15 most recent commands
- Persistent storage across shell sessions
- Command deduplication (consecutive duplicates ignored)
- Indexed execution for quick replay
Display all running and stopped background processes.
Syntax:
activitiesOutput Format:
[job_number] : command - Status
Example Output:
[1] : sleep 100 - Running
[2] : vim file.txt - Stopped
Features:
- Lexicographically sorted by command name
- Shows job number, command, and status
- Status: Running or Stopped
Send signals to processes by PID.
Syntax:
ping <pid> <signal_number>Examples:
ping 1234 9 # Send SIGKILL (signal 9) to process 1234
ping 5678 15 # Send SIGTERM (signal 15) to process 5678Features:
- Signal number modulo 32 for safety
- Process existence validation
- Error handling for invalid PIDs
Bring a background or stopped job to the foreground.
Syntax:
fg <job_number>Examples:
fg 1 # Bring job [1] to foregroundFeatures:
- Resumes stopped jobs
- Waits for job completion
- Updates job status
Resume a stopped job in the background.
Syntax:
bg <job_number>Examples:
bg 2 # Resume job [2] in backgroundFeatures:
- Sends SIGCONT to stopped jobs
- Updates job status to running
- Non-blocking operation
Append & to run commands in the background:
sleep 100 &
firefox &
./long_running_script.sh &Features:
- Automatic job number assignment
- Non-blocking execution
- Process completion notifications
Input Redirection:
wc < input.txt
./program < data.txtOutput Redirection:
ls > output.txt # Overwrite
echo "text" >> file.txt # AppendCombined:
sort < input.txt > sorted.txtChain multiple commands:
ls -l | grep ".c" | wc -l
cat file.txt | sort | uniq | grep "pattern"
ps aux | grep "process" | awk '{print $2}'Features:
- Unlimited pipe chaining
- Efficient inter-process communication
- Proper error handling
Sequential Execution (;):
cd src ; ls ; pwdExecutes all commands sequentially, regardless of success/failure.
Conditional Execution (&&):
make clean && make all && ./shell.outExecutes next command only if previous succeeded.
Background Execution (&):
command1 & command2 & command3All commands run in background simultaneously.
- Ctrl+C (SIGINT): Terminates foreground process, shell continues
- Ctrl+Z (SIGTSTP): Stops foreground process, moves to background
- Ctrl+D (EOF): Graceful shell exit with cleanup
- SIGCHLD: Automatic background process reaping
C-Shell/
βββ Makefile # Build configuration
βββ README.md # This file
βββ requirements.txt # Python test dependencies
βββ shell.tcl # TCL test script
βββ test.py # Python test suite
βββ shell.out # Compiled executable (after build)
β
βββ data/ # Runtime data files
β βββ logs.txt # Command history storage
β βββ logs_stat.txt # Log metadata
β
βββ include/ # Header files
β βββ header.h # Main header with declarations
β
βββ src/ # Source files
β βββ main.c # Entry point and main loop
β βββ prompter.c # Shell prompt display
β βββ tokeniser.c # Input tokenization
β βββ parser.c # Command parsing
β βββ executor.c # Command execution engine
β βββ function.c # Built-in command implementations
β βββ log_ops.c # Command history operations
β βββ job_manager.c # Background job management
β βββ signal_handler.c # Signal handling logic
β βββ utility.c # Utility functions
β
βββ build/ # Object files (generated)
β βββ *.o # Compiled object files
β
βββ __pycache__/ # Python cache (generated)
pip install -r requirements.txtThis installs:
pytest- Testing frameworkpexpect- Process control and automationpsutil- Process and system monitoring- Additional dependencies for test execution
pytest test.py -vTest Coverage:
- Shell prompt format validation
- Built-in command functionality
- I/O redirection operations
- Piping mechanisms
- Background process handling
- Signal handling behavior
# Start the shell
./shell.out
# Test basic commands
<user@host:~> ls -la
<user@host:~> pwd
# Test built-in commands
<user@host:~> hop ..
<user@host:/home> reveal -al
<user@host:/home> log
# Test I/O redirection
<user@host:~> echo "Hello" > test.txt
<user@host:~> cat < test.txt
# Test piping
<user@host:~> ls | grep ".c"
# Test background jobs
<user@host:~> sleep 50 &
<user@host:~> activitiesThe tokenizer (tokeniser.c) converts raw input into structured tokens:
Token Types:
NAME- Command names and argumentsPIPE- Pipe operator (|)INPUT/OUTPUT- I/O redirection (<,>,>>)AND- Conditional execution (&&)SEMICOLON- Sequential execution (;)BACKGROUND- Background execution (&)END- End of input
The recursive descent parser (parser.c) validates command syntax:
parse β cmd_group [(&& | ;) cmd_group]* [&]
cmd_group β atomic [| atomic]*
atomic β NAME [INPUT | OUTPUT]*
The executor (executor.c) handles:
- Command type identification (built-in vs system)
- Process creation (
fork()for system commands) - I/O redirection setup
- Pipe creation and management
- Background job tracking
- Error handling and recovery
Background jobs are tracked using a job list:
typedef struct {
pid_t pid; // Process ID
char command[MAX_LENGTH]; // Command string
int job_number; // Job identifier
int status; // 0=running, 1=stopped
} Job;Operations:
add_job()- Register new background jobremove_job()- Remove completed jobget_job_by_number()- Lookup by job numberupdate_job_status()- Update job state
Persistent logging system (log_ops.c):
- Stores commands in
data/logs.txt - Maintains metadata in
data/logs_stat.txt - Circular buffer for 15 most recent commands
- Automatic deduplication
-
SIGINT (Ctrl+C)
- Terminates foreground process only
- Shell remains active
- No effect if no foreground process
-
SIGTSTP (Ctrl+Z)
- Stops foreground process
- Converts to background job
- Job can be resumed with
fgorbg
-
SIGCHLD
- Automatic zombie process reaping
- Background job completion notification
- Non-blocking status checks
void setup_signal_handlers() {
signal(SIGINT, handle_sigint);
signal(SIGTSTP, handle_sigtstp);
signal(SIGCHLD, handle_sigchld);
}Remove compiled files and reset the build:
make cleanThis removes:
build/directory and all object filesshell.outexecutable
Error: gcc: command not found
# Install GCC on Ubuntu/Debian
sudo apt-get update
sudo apt-get install build-essential
# Install on macOS
xcode-select --installError: Missing headers
- Ensure you're on a POSIX-compliant system
- Check that all source files are present in
src/
Issue: Command not found
- Ensure the command exists in your system PATH
- Use absolute paths for custom executables
Issue: Background jobs not showing
- Use
activitiesto list all jobs - Check if processes terminated immediately
Issue: Signal handling not working
- Verify you're running on a Unix-like system
- Check terminal emulator compatibility
- The shell maintains its own home directory context from startup
- Previous directory (
hop -) is tracked per shell session - Command history persists across shell sessions
- Maximum 15 commands stored in history (configurable in
header.h) - Maximum 256 background jobs supported (configurable in
header.h)
Contributions are welcome! To contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is part of an academic assignment. Please refer to your institution's policies on code sharing and collaboration.
TECHIE-TITAN
- GitHub: @TECHIE-TITAN
- Repository: C-Shell
- Unix/Linux shell documentation and man pages
- POSIX standards for system calls
- Course instructors and teaching assistants
- Open-source community for inspiration
Last Updated: October 2025
For issues, questions, or suggestions, please open an issue on the GitHub repository.