Tiny Shell Exercise
The goal of this exercise is to complete writing a simple Unix shell program that executes user commands. Last
class we wrote a simple program that reads user commands in a loop and executes the command
ls -l
regardless of user input. For your reference, we include the code below.
#include <stdio.h>
#define MAXCMD 100
char *cmdarg[] = {"ls", "-l", 0};
char cmdbuf[MAXBUF]; // used to store the input command
int main()
{
int ret;
while(1)
{
printf("\ntsh>"); fflush(stdout); // force prompt onto the screen
fgets(cmdbuf, MAXBUF, stdin); // read user command
// Should tokenize cmdbuf and store tokens into cmdarg
// Instead, we simply execute ls
if(strcmp(cmdbuf, "quit\n") == 0)
exit(0);
ret = fork(); // create new process
if(ret == 0)
{
// Child code
execvp("ls", cmdarg);
printf("\nChild done\n");
}
else
{
// Parent code
wait(0);
printf("\nParent done\n");
}
}
}
To help you finish the shell, we also
implemented a function called parseline that parses the user command and builds the array of tokens (ASCII
text words delimited by whitespaces). To use this function, you must allocate space for the array of arguments
and pass it as a second argument to the function, as follows:
#define MAXARGS 20
// ...
char * cmdarg[MAXARGS];
// ...
parseline("ls -l\n", cmdarg);
The call above would set
cmdarg[0] = "ls";
cmdarg[1] = "-l";
cmdarg[2] = 0;
The code for the parseline function is appended below. Your job is to complete the tiny shell. Your
shell should be able to execute simple commands such as
ls -l
ps -ef
finger mdamian
grep 'const char *' yourshell.c
Submit a printed copy of your code (which should be well documented)
and a sample output. Have fun!
/*
* parseline - Parse the command line and build the argv array.
*
* Characters enclosed in single quotes are treated as a single argument.
*/
void parseline(const char *cmdline, char **argv)
{
static char array[MAXLINE]; /* holds local copy of command line */
char *buf = array; /* ptr that traverses command line */
char *delim; /* points to first space delimiter */
int argc; /* number of args */
strcpy(buf, cmdline);
buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */
while (*buf && (*buf == ' ')) /* ignore leading spaces */
buf++;
/* Build the argv list */
argc = 0;
if (*buf == '\'') {
buf++;
delim = strchr(buf, '\'');
}
else {
delim = strchr(buf, ' ');
}
while (delim) {
argv[argc++] = buf;
*delim = '\0';
buf = delim + 1;
while (*buf && (*buf == ' ')) /* ignore spaces */
buf++;
if (*buf == '\'') {
buf++;
delim = strchr(buf, '\'');
}
else {
delim = strchr(buf, ' ');
}
}
argv[argc] = NULL;
}