A pedagogical exercise in recreating a basic shell's essential mechanisms. Part of the developer program at the Holberton School which follows a project-based learning approach.
simple_shell is a minimalist Unix command-line interpreter written in C. This
simple_shell attempts to emulate the behavior of sh, but ignores
command-line options and arguments. It has two modes of operation: interactive
and non-interactive. Interactive mode is the mode by default, it is initiated
by executing the simple_shell program. Non-interactive mode is entered when
commands piped into the standard input of simple_shell.
- In interactive mode, a prompt is displayed and the program awaits input from
the user. Once a command is executed and an output (if any) is displayed, a new
prompt is displayed and a new input is awaited. To exit the interactive mode and
terminate the program two methods are available:
EOFemulation (Ctrl+D) and the built-in commandexit. - In non-interactive mode, no prompt is made, the commands are executed, output (if any) is displayed, and the program terminates.
Our shell can handle the commands existing in the "PATH" environment variable and the following built-ins : exit, env.
It could be improved by :
- Handling
Ctrl+C, the shell should not quit when it is used, - Implementing more built-ins functions like
setenv,unsetenv,cd,help,aliasandhistory, - Handling the command separator
;, - Handling the
&&and||logical operators, - Handling variable replacement,
- Handling
$$and$?variables, - Handling comments with
#, - Handling files as input.
gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c -o simple_shell
We have been required to make our code compilation-ready under systems with
Ubuntu 20.04 LTS and using gcc as a compiler. Additionally, the compiler would
use the flags -Wall -Werror -Wextra -pedantic -std=gnu89 and all our codes must
follow the Betty coding style (which limits the length of our programs, among
other things).
Moreover, we may not have more than 5 functions per file, all header files must
be include-guarded, and system calls must be used only when necessary.
The output and error output should be the same as those of sh in most
cases.
Team work, collaboration, and the methodology of equitative contributions were strictly observed.
We were authorized to use only the following functions and system calls:
| all functions from string.h | getpid (man 2 getpid) | readdir (man 3 readdir) |
| access (man 2 access) | isatty (man 3 isatty) | signal (man 2 signal) |
| chdir (man 2 chdir) | kill (man 2 kill) | stat (__xstat) (man 2 stat) |
| close (man 2 close) | malloc (man 3 malloc) | lstat (__lxstat) (man 2 lstat) |
| closedir (man 3 closedir) | open (man 2 open) | fstat (__fxstat) (man 2 fstat) |
| execve (man 2 execve) | opendir (man 3 opendir) | strtok (man 3 strtok) |
| exit (man 3 exit) | perror (man 3 perror) | wait (man 2 wait) |
| _exit (man 2 _exit) | printf (man 3 printf) | waitpid (man 2 waitpid) |
| fflush (man 3 fflush) | fprintf (man 3 fprintf) | wait3 (man 2 wait3) |
| fork (man 2 fork) | vfprintf (man 3 vfprintf) | wait4 (man 2 wait4) |
| free (man 3 free) | sprintf (man 3 sprintf) | write (man 2 write) |
| getcwd (man 3 getcwd) | putchar (man 3 putchar) | |
| getline (man 3 getline) | read (man 2 read) |
Here are some examples of the use of our shell :
valentin@Valou-PC:~/holbertonschool-simple_shell$ ./simple_shell
$ ls
README.md Shared_diagram-VD.jpg VD_tests builtin.c exec.c generate-authors.sh helper.c hsh main.c path.c read.c shell shell.h split.c
$ pwd
/home/valentin/holbertonschool-simple_shell
$ exit
valentin@Valou-PC:~/holbertonschool-simple_shell$
The man page provides a detailed explanation of the function. To see the full
documentation, read our man page by doing :
man ./man_1_simple_shell while in the same directory.
We have made a testing program to test different cases of command and error code handling. Here are some examples of output from the test:
Command: unknowcmd
Expected exit: 127 | Got: 127
Expected output (part): "not found"
Shell output:
./simple_shell: 1: unknowcmd: not found
TEST ✅ PASSED
Command: ls /doesnotexist
Expected exit: 2 | Got: 2
Expected output (part): "No such file or directory"
Shell output:
ls: cannot access '/doesnotexist': No such file or directory
TEST ✅ PASSED
Command: exit
Expected exit: 0 | Got: 0
Expected output (part): ""
Shell output:
TEST ✅ PASSED
We also used valgrind to be sure there are no memory leaks :
valgrind ./simple_shell
We have made a flowchart to facilitate the comprehension of our algorithm :

main.c: entry point, core of the program.shell.h: header file containing all library inclusions as well as all the function prototypes, and structures used bysimple_shell.read.c: file containing the function to read user's input.split.c: contains the function that tokenize the input, such that the first token (of each read line) may be used as a command and the rest as that commands options.builtin.c: contains the built-in functions and another that checks if the used command is part of the available builti-in's.helper.c: contains some helper functions for the functions who offer actual program functionalities.exec.c: contains the function that handles command execution.path.c: contains the function that finds the command in the system PATH (when the command was not given as a path to the executable).
- Valentin Dumont : github.com/Proser-V
- Hamza Hammadi : github.com/Hamza-coder3011
- Xavier Laforgue : github.com/XavierLaforgue