A robust, POSIX-compliant Unix shell implementation featuring a complete lexer-parser-executor pipeline architecture. Built to be resilient against edge cases and malformed input.
valiantshell is a fully-featured Unix shell written in C as part of the 42 School curriculum. The project reimplements core bash functionality with emphasis on robustness, memory safety, and proper signal handling. The shell handles complex command pipelines, redirections, environment variable expansion, and built-in commands while maintaining compatibility with standard shell behavior.
The architecture follows a clean separation of concerns with distinct modules for tokenization, parsing into an abstract syntax tree (AST), variable expansion, and execution. This design enables comprehensive error handling at each stage and makes the codebase maintainable and extensible.
- Command Execution: Execute external programs with PATH resolution and argument handling
- Pipeline Support: Chain multiple commands with
|pipes for data streaming - I/O Redirections: Full support for
<,>,>>, and<<(here-documents) - Environment Variables: Expansion of
$VAR,$?(exit status), and quoted variables - Built-in Commands: Native implementation of
echo,cd,pwd,export,unset,env,exit - Wildcard Expansion: Glob pattern matching with
*for filename expansion - Signal Handling: Proper handling of Ctrl+C, Ctrl+D, and Ctrl+\ with context awareness
- Quote Processing: Support for single quotes (literal) and double quotes (with expansion)
- History: Command history with readline integration
- Error Handling: Graceful handling of syntax errors, permission issues, and edge cases
- Architecture: Four-stage pipeline: Lexer → Parser → Expander → Executor
- Memory Safety: Zero memory leaks verified with Valgrind and AddressSanitizer
- Robustness: Extensive fuzzing and edge case testing for stability
- POSIX Compliance: Behavior matches bash for standard shell operations
- Signal Safety: Async-signal-safe signal handlers with proper terminal control
┌─────────────────────────────────────────────────────────────────┐
│ Input (readline) │
│ "ls -la | grep .c > out.txt" │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LEXER │
│ Tokenization with quote and escape handling │
│ ["ls", "-la", "|", "grep", ".c", ">", "out.txt"] │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ PARSER │
│ Build Abstract Syntax Tree from token stream │
│ │
│ [PIPE] │
│ / \ │
│ [CMD ls] [REDIRECT >] │
│ | | │
│ [-la] [CMD grep] │
│ | │
│ [.c] │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ EXPANDER │
│ Variable expansion, wildcard glob, quote removal │
│ $HOME → /home/user, *.c → [file1.c, file2.c] │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ EXECUTOR │
│ Fork processes, setup pipes/redirects, execute commands │
│ Handle built-ins directly, externals via execve │
└─────────────────────────────────────────────────────────────────┘
| Command | Description |
|---|---|
echo |
Display text with -n flag support for no newline |
cd |
Change directory with ~, -, and path support |
pwd |
Print current working directory |
export |
Set or display environment variables |
unset |
Remove environment variables |
env |
Display all environment variables |
exit |
Exit the shell with optional exit code |
| Operator | Description |
|---|---|
| |
Pipe output from left command to right command |
< |
Redirect input from file |
> |
Redirect output to file (overwrite) |
>> |
Redirect output to file (append) |
<< |
Here-document (read input until delimiter) |
$VAR |
Environment variable expansion |
$? |
Exit status of last command |
* |
Wildcard glob pattern matching |
'...' |
Single quotes (literal string, no expansion) |
"..." |
Double quotes (allows $ expansion) |
- Operating System: Linux, macOS
- Compiler: GCC or Clang with C99 support
- Libraries: readline, ncurses
- Build Tools: GNU Make
Ubuntu/Debian:
sudo apt-get install libreadline-dev libncurses-devmacOS (Homebrew):
brew install readlinegit clone --recursive https://github.com/TheValiant/valiantshell.git
cd valiantshell
make./minishell$ ./minishell
valiantshell$ echo "Hello, World!"
Hello, World!
valiantshell$ export NAME=User
valiantshell$ echo "Welcome, $NAME"
Welcome, User
valiantshell$ ls -la | grep ".c" | wc -l
42
valiantshell$ cat << EOF > greeting.txt
> Hello from here-doc!
> EOF
valiantshell$ cat greeting.txt
Hello from here-doc!
valiantshell$ cd /tmp && pwd
/tmp
valiantshell$ exit| Feature | valiantshell | bash |
|---|---|---|
| Pipes | Supported | Supported |
Redirections (<, >, >>) |
Supported | Supported |
Here-documents (<<) |
Supported | Supported |
| Environment variables | Supported | Supported |
Exit status ($?) |
Supported | Supported |
Wildcards (*) |
Supported | Supported |
| Single and double quotes | Supported | Supported |
| Built-in commands | Supported | Supported |
| Signal handling | Supported | Supported |
| Command history | Supported | Supported |
Logical operators (&&, ||) |
Not implemented | Supported |
Subshells () |
Not implemented | Supported |
Background jobs (&) |
Not implemented | Supported |
| Scripting | Not implemented | Supported |
The shell has been extensively tested with:
- Edge cases for quote handling and escape sequences
- Memory leak detection with Valgrind
- AddressSanitizer for memory safety
- Fuzzing with various input generators
- Comparison testing against bash behavior
This project provided deep experience in:
- Process management with fork, execve, pipe, dup2
- File descriptor manipulation and I/O redirection
- Signal handling in multi-process environments
- Lexer and parser design for language processing
- Memory management in long-running applications
- Terminal control and readline integration
valiantshell/
├── src/
│ ├── main.c # Entry point
│ ├── minishell.h # Main header
│ ├── builtins/ # Built-in command implementations
│ ├── destroyers/ # Memory cleanup functions
│ ├── execution/ # Command execution and piping
│ ├── exit_metadata/ # Exit status management
│ ├── expanders/ # Variable and wildcard expansion
│ ├── history/ # Command history handling
│ ├── initializers/ # Shell initialization
│ ├── input_fortification/ # Input validation
│ ├── parsing/ # Tokenizer and AST builder
│ ├── signals/ # Signal handlers
│ ├── string_tools/ # String utilities
│ └── syscall_wrappers/ # Safe syscall wrappers
├── libft/ # Custom C library
├── Makefile
└── README.md
- 42 School for the project specifications
- GNU Bash documentation for reference behavior
- The readline library maintainers
This project is available under the MIT License. See LICENSE for details.
Note: This project was completed as part of the 42 School curriculum, which emphasizes peer-to-peer learning and project-based education in software engineering.