Laboratory Exercises For Computer Science 213

A Simple Unix-Style Shell

A Simple Unix-Style Shell

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:

  1. setting or modifying an environmental variable, such as the current working directory or the search path, and
  2. executing commands or programs issued by the user.

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.

  1. 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.

  2. Type the command echo $PWD to check that this returns the same directory as given by the pwd command.

  3. Review the results of the echo $PATH command, to be sure you know what order directories are searched for a command.

    1. In what directory is the pwd command located?
    2. In what directory is the C-compiler gcc command located?

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.

  1. Copy ~walker/c/shell-programs/env-test.c to your account, compile it with gcc, run it, and explain the results.

  2. 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.

  3. 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.

  1. Copy ~walker/c/shell-programs/my-shell.c to your account, compile it, and run it.

    1. Within the shell, issue the pev and setp commands and check that this shell runs as expected.
    2. Issue regular commands (e.g., pwd or ls -l) to check that these produced the familiar output.

  2. 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.

    1. What initialization is done within the main, and why do you think the variables are initialized as shown?
    2. What is the purpose of procedures print_env_var and read_line?
    3. How are commands pev and setd handled by the shell?
    4. What general approach is followed for the handling of commands that do not involve environmental variables?
    5. Why do you think the code skips the rest of the loop with a continue statement if a command_name is NULL?

  3. 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).

  1. 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.

  2. Using the man execvp command in a terminal window as a guide, explain what the execvp statement does in the code.

  3. 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.

  4. 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 /.)

  5. 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.

    1. Declare a working_str as an array of characters, and copy PATH to working_string using strcpy (working_string, PATH);

    2. 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?)

    3. 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);
      
    4. 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.

    5. 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.

    6. 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.

Work to be turned in: Note: For most steps, it is expected that the answer will be short.


This document is available on the World Wide Web as

     http://www.math.grin.edu/~walker/courses/213.fa00/lab-shell.html

created September 25, 2000
last revised September 26, 2000