Goals: To investigate and expand a simple shell program, following the same style as the Unix Bourne, sh, csh, and bash shells.
Background Reading: Nutt, Chapter 2, Lab Exercise, pp. 47-54.
Discussion: A traditional interface for interactive computing is a Unix shell. While modern Unix shells include extensive capabilities, a simple shell facilitates two types of interactions:
Environmental Variables: To simplify interactions with a user, a shell maintains a collection of environmental variables. On Unix systems, two such variables are PWD and PATH. PWD holds the user's working directory, and PATH contains a sequence of directories -- separated by colons, indicating where to search for commands issued by the user.
Open a terminal window, and type the commands pwd and echo $PATH
The first of these commands returns the value of the PWD variable, while the second shows a more generic way of displaying the value of any environmental variable.
Type the command echo $PWD to check that this returns the same directory as given by the pwd command.
Review the results of the echo $PATH command, to be sure you know what order directories are searched for a command.
Program ~walker/c/shell-programs/env-test.c illustrates the use of procedures getenv and setenv within a C program to read and modify environmental variables, respectively.
Copy ~walker/c/shell-programs/env-test.c to your account, compile it with gcc, run it, and explain the results.
Use the echo $PATH command to determine the initial path for the window's shell. Then run env-test and use echo $PATH. Is the PATH of the window shell changed? Explain briefly.
Modify env-test.c so that it retrieves and changes the environmental variable PWD to refer to a designated directory in your account -- other than the directory containing the env-test.c program. Compile and run the revised program, and indicate its output.
A Shell Shell: Program ~walker/c/shell-programs/my-shell.c contains the beginnings of a simple shell program. Specifically, the program processes two special environmental-variable commands:
my-shell.c also contains a facility for handling commands that do not affect environmental variables.
Note, however, that the current my-shell.c does not use either its PWD or PATH programs in processing -- referring instead to the corresponding variables of the original window.
Copy ~walker/c/shell-programs/my-shell.c to your account, compile it, and run it.
Review the basic structure of my-shell. To clarify your understanding of the program, answer each of the following questions in a sentence or two.
Why do you think the commands involving environmental variables are handled differently from other commands?
The strtok scans a string for a given token. Thus, command_name = strtok(command_line, " "); scans the command_line for the first space. All characters before that space are assigned to command_name, and hidden variables remember the rest of the string after the space. Further, when the first parameter to strtok is NULL, then strtok continues scanning the string it processed previously to determine the location of the next token. More information may be obtained by typing man strtok in a terminal window.
The execvp command takes two arguments: the name of the command, and an array containing pointers to the command's string arguments (starting with the command name itself).
Processing of non-environment-related commands contains the code
/* set up array of command arguments */
command_args[0] = command_name;
num_args = 1;
command_args[num_args] = strtok(NULL, " ");
while (command_args[num_args] != NULL) {
num_args++;
command_args[num_args] = strtok(NULL, " ");
}
Explain what this code does and how that task is accomplished. Also, when the code is done, clarify what is stored in command_args[num_args], and briefly explain your answer.
Using the man execvp command in a terminal window as a guide, explain what the execvp statement does in the code.
Running this preliminary shell program again in a terminal window, type in an invalid program name and see what happens. Explain how the output is generated.
Expand my-shell.c so that it processes a setd command, that sets the current directory PWD to the string specified. (You may assume that the string gives an absolute path name -- starting with /.)
Modify my-shell.c, so that searching is done based on my-shell.c's variables PWD and PATH, rather than those set in the terminal window.
Declare a working_str as an array of characters, and copy PATH to working_string using strcpy (working_string, PATH);
Use a loop involving strtok and the token : to identify successive directories in the PATH. (Actual processing should use working_string rather than PATH, however. Why?)
Given a directory, represented as a string dir_str, a command name command_name, and an array of characters full_command_string, form the full command (with path name) by the sequence:
strcpy (full_command_string, dir_str); strcat (full_command_string, command_name);
Use the fopen statement -- opening for reading -- to test if the command is located at a specified location (e.g., full_command_string). (An error on opening indicates the file does note exist.) As with other commands, details of fopen may be found by typing man fopen.
Upon finding the full path name for a command using fopen, close the file, and call execv -- which is just like execvp, except that the first parameter should be the full path name rather than just the program name.
Adjust your program as necessary, so that the directory <dot> (.) on the search path refers to the directory given by PWD, rather than any directory that might be specified in the terminal window.
This document is available on the World Wide Web as
http://www.math.grin.edu/~walker/courses/213.fa00/lab-shell.html