This project implements a simple UNIX command interpreter written in C.
It was developed as part of the Holberton School curriculum and is designed to reproduce the basic behavior of a UNIX shell (sh).
The shell can run both in interactive mode and non-interactive (pipeline) mode, execute commands found in the system's $PATH, and handle a small set of built-in commands.
This project demonstrates process creation, PATH resolution, file execution, environment management, and robust error handling.
- Interactive mode with the prompt
($) - Non-interactive mode (commands through pipeline or file)
- Command execution using both absolute paths and
$PATHlookup - Built-in commands:
exitandenv - Handling of whitespace, empty lines, and input formatting
- Proper exit status management (0, 126, 127, 128+signal)
- Error messages formatted like a UNIX shell
- Modular architecture for maintainability and clarity
- Ubuntu 20.04 LTS
gcccompiler- Betty style compliance
To compile the program, use:
gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c -o hshUsage Interactive Mode
Run the program as follows: ./hsh
The shell will display:
($)
Then wait for commands such as:
($) ls
($) /bin/pwd
($) env
($) exit
Non-interactive Mode
In non-interactive mode, the shell reads commands from standard input and executes them sequentially, without displaying the prompt. Commands can be piped into the shell:
echo "ls" | ./hsh
echo "pwd" | ./hsh
printf "ls\nwhoami\n" | ./hsh
.
├── README.md # Project documentation
├── man_1_hsh # Manual page (man 1 hsh)
├── shell.h # Header file (function prototypes + libraries)
│
├── builtin.c # Built-in functions (exit, env)
├── error.c # Error handling and formatted messages
├── execute.c # Forking and executing commands
├── loop.c # Main loop, I/O handling, mode selection
├── parsing.c # Input formatting, tokenizing, memory handling
├── path.c # PATH lookup, env value management
├── path_utils.c # Helpers for building and validating paths
└── prompt.c # Prompt printing in interactive mode
-
exit
Exit the shell (no arguments supported). -
env
Print the current environment variables.
The shell supports:
Absolute path commands: /bin/ls, /bin/pwd, /usr/bin/whoami, etc.
Commands located through $PATH:
ls, pwd, echo, etc.
This shell does not support:
- Pipes (|)
- Redirections (<, >, >>)
- Command chaining (&&, ||)
- Wildcards (*)
- Aliases
- Signal handling (Ctrl+C behavior is default)
Programs available in custom PATH directories
Usage Examples
$ ./hsh
($) ls
builtin.c error.c execute.c hsh loop.c parsing.c path.c path_utils.c prompt.c shell.h
($) /bin/pwd
/home/user/simple_shell
($) whoami
user
($) env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/home/user
...
($) exit
$
This shell uses the environment variables inherited from the parent process.
The PATH environment variable is used to locate executable files when
commands are not provided with an absolute or relative path.
The shell does not modify the environment but passes it directly to executed
programs using execve.
This shell implements structured error messages similar to /bin/sh, using the format:
program_name: line_number: command: error_message
Examples:
./hsh: 3: aaa: not found
./hsh: 5: ./dir: Permission denied
./hsh: 7: /bin/shh: No such file or directory
- Command not found
- Permission denied / not executable
- No such file or directory
- Child process terminated by a signal
- Internal errors (e.g.
fork/waitpidfailure)
- Returns 0 on successful execution
- Returns 126 when a command is found but not executable
- Returns 127 when a command is not found
- Returns 128 + signal number when terminated by a signal
A manual page is provided for this shell.
File: hsh.1
Section: 1 (User Commands)
You can view it with: man ./hsh.1
You can also preview the manual page here :
- Initialize variables and determine if the shell is running in interactive mode using
isatty. - If running in interactive mode, display the prompt (
$). - Read a line from standard input using
getline. - Clean and normalize the input line:
- Remove the trailing newline
- Trim leading and trailing whitespace
- If the line is empty or contains only whitespace, restart the loop.
- Split the input line into tokens (command only, no arguments).
- Check if the command is a built-in:
exitenv
- If the command is not a built-in:
- Determine how to resolve the command:
- Use the command directly if it contains a
/ - Otherwise, search for it in the
PATH
- Use the command directly if it contains a
- Fork a child process.
- Execute the command using
execve. - If execution fails, print the appropriate error message.
- Determine how to resolve the command:
- In the parent process, wait for the child process using
waitpid. - Retrieve and store the exit status of the command.
- Repeat the loop until
exitis called or EOF is reached.
A graphical flowchart can be added in a subdirectory, for example:
and referenced from this README.
Compilation Check
gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c -o hsh
Memory Leak Check (Valgrind)
valgrind --leak-check=full ./hsh
- Morgane abbattista (Alreix)
- GitHub: https://github.com/Alreix
This project is part of the Holberton School curriculum and is provided for educational purposes.

