A Unix-like command line interpreter built from scratch in C. Features robust process creation via fork/exec, signal handling, persistent history, and built-in navigation commands.
The shell operates on a standard Read-Eval-Print Loop (REPL). For external commands, it utilizes the fork() system call to create a child process and execvp() to replace the child's memory space with the new program. The parent process uses waitpid() to pause until execution completes.
While most commands (like ls or grep) are external programs, commands that modify the shell's own state must be built-in.
Implemented cd using the chdir() syscall. Supports logic for ~ (home), - (previous), and error handling for invalid paths.
Commands are appended to a hidden .history.txt file. On startup, the last 10 lines are loaded into memory for quick access.
The shell processes raw user input by tokenizing the command line string into a null-terminated array of arguments (`char **`). It utilizes strtok to split the string by spaces and includes a sanitization step to strip the trailing newline character typically left by input reading functions.
char **parse_args(char *line)
{
char **args = malloc(1024 * sizeof(char *));
char *arg = strtok(line, " ");
int i = 0;
while (arg != NULL)
{
args[i] = arg;
arg = strtok(NULL, " ");
i++;
}
args[i] = NULL;
// Remove the trailing newline from the last argument
// so execvp doesn't fail on command lookup
args[i - 1][strlen(args[i - 1]) - 1] = '\0';
return args;
}