Writing a Basic Shell Writing a Basic Shell shell shell

Writing a Basic Shell


It really depends on how simple your shell has to be. If you don't need job control (i.e. backgrounding) or pipes then it is very simple. Here is an example:

#include <stdio.h>#include <stdlib.h>#define MAX_LENGTH 1024int main(int argc, char *argv[]) {  char line[MAX_LENGTH];  while (1) {    printf("$ ");    if (!fgets(line, MAX_LENGTH, stdin)) break;    system(line);  }  return 0;}

You can exit from the above example with CTRL-D. To add built-in commands like exit or cd you would have to tokenize the line using strtok() and look at the first token. Here is a more complicated example with those commands added:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#ifdef _WIN32#include <windows.h>#define chdir _chdir#else#include <unistd.h>#endif#define MAX_LENGTH 1024#define DELIMS " \t\r\n"int main(int argc, char *argv[]) {  char *cmd;  char line[MAX_LENGTH];  while (1) {    printf("$ ");    if (!fgets(line, MAX_LENGTH, stdin)) break;    // Parse and execute command    if ((cmd = strtok(line, DELIMS))) {      // Clear errors      errno = 0;      if (strcmp(cmd, "cd") == 0) {        char *arg = strtok(0, DELIMS);        if (!arg) fprintf(stderr, "cd missing argument.\n");        else chdir(arg);      } else if (strcmp(cmd, "exit") == 0) {        break;      } else system(line);      if (errno) perror("Command failed");    }  }  return 0;}

You could extend this by adding more build-in commands or by supporting things like cd with out arguments to change to your home directory. You could also improve the command prompt by adding information such as the current directory.

As a side note, an easy way to add a command history and line editing features is to use the GNU readline library.


I wrote a very basic shell for the HelenOS project. It has the following features:

  • Line editing / history
  • Buit in commands / loadable commands
  • Search path to find external commands
  • EXTREMELY basic scripting
  • Dumbed down implementations of most of the GNU core utilities (done from scratch) as built in functions.

Most of it is implemented on a very simple re-usable framework built around function pointers. At the minimum, you'll need a built in 'exit' or 'quit' so someone can actually get out of the shell, plus 'cd' and 'pwd'. An 'export' / 'declare' built in would also make sense.

You can look at the code (BSD) licensed here. Or download the repo, it's in uspace/app/bdsh. I can probably dig up the last working Linux version, prior to when I ported it if you need it. The biggest difference is the HelenOS version uses a home grown line editor, task_spawn() instead of execve() / posix_spawn(), etc. The rest is portable. It was originally designed just to make testing of features easy and interactive. I didn't implement job control, as it wasn't needed. That could be achieved trivially, however.

If you want to study a 'real' shell, I highly recommend looking at dash, you'll find it much simpler to grasp than diving straight into the code of bash.

Anecdotally, 'bdsh' stands for 'brain dead shell'.


You could look at BusyBox for some very small shell implementations.