为什么 execvp 只对我 shell 中输入的第一个命令有效?

Why does execvp only work for the first command entered in my shell?

#include <stdio.h>
#include <string.h>
#include <cstring>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

char input[100];
#define DELIMITERS " \t\n"
char * tokens[100];
int numTokens = 0;
int i = 0;
int n = 0;
char * cmd;

// function prototype
void nonBuiltin(char * inputs[]);
void handlePipe(char * cmds[]);

// this breaks the input into tokens and returns them
char * tokenize(char input[100])
{
  n = 0;
  // grabs input and separates by delimiters until the char is null
  for(cmd = strtok(input, DELIMITERS); cmd; cmd = strtok(NULL, DELIMITERS))
    {
      if(n >= 100)
       {
         break;
       }
      tokens[n++] = cmd;
      numTokens++;
    } 

    for(size_t i = 0; i != n; i++)
      {
        printf("Tokens %zu is %s\n", i, tokens[i]);
      }
    return * tokens;
}

// handles the commands you enter
// checks if builtin or non builtin command
// if builtin, execute command
// else, send command to nonbuiltin function
void handleCommands(char * inputs)
{
  // changes directory
  if(strcmp(tokens[0], "cd") == 0)
    {
      int change = chdir(tokens[1]);
      if(change == 0)
        {
          chdir(tokens[1]);
        }
      else
        {
          perror("Cannot find path specified...\n");
        }
    }
  // prints working directory
  else if(strcmp(tokens[0], "pwd") == 0)
    {
      printf("Your current working directory is: %s\n", getenv("PWD"));
    }
  // implements set command
  else if(strcmp(tokens[0], "set") == 0)
    {
      // do this
    }
  // exits program
  else if(strcmp(tokens[0], "exit") == 0)
    {
      printf("Now exiting...\n");
      exit(3);
    }
  // input contains a nonbuiltin command
  // sends input to nonbuiltin function
  else
    {
      printf("Your command is a nonbuilt-in command\n");
      nonBuiltin(tokens);
    }
}

void nonBuiltin(char * inputs[])
{
  int fp;
  int status;

  // create a new process
  pid_t pid;
  pid = fork();
  // process creation was unsuccessful
  if(pid < 0)
    {
      perror("Fork unsuccessful...\n");
      exit(-1);
    }
  // child process
  else if(pid == 0)
    {
      // printf("Fork successful...\n");
      if(numTokens >= 3)
    {
      for(int i = 0; i < numTokens; i++)
        {
          if(strcmp(tokens[i], "<") == 0)
          {
            tokens[i] = tokens[i+1];
            fp = open(tokens[i], O_RDONLY, 0);
            dup2(fp, 0);
            execvp(tokens[0], tokens);
          }
          else if(strcmp(tokens[i], ">") == 0)
          {
            tokens[i] = tokens[i+1];
            fp = open(tokens[i], O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
            dup2(fp, 1);
            close(fp);
            tokens[i]= NULL;
            execvp(tokens[0], tokens);

          }
          else if(strcmp(tokens[i], "|") == 0)
            {
              tokens[i] = tokens[i+1];
              handlePipe(tokens);
            }
        }
    }

      else
      {
       // printf("Nothing special as far as commands go\n");
       execvp(tokens[0], tokens); 


      }
    }
  // wait for child process to end
  else
    {
      waitpid(-1, &status, WUNTRACED);
      printf("the child process has now terminated\n");
     // exit(0);
    }

}


void handlePipe(char * cmds[])
{
    printf("Initiate piping\n");
    // file descriptors
    int fd[2];
    // fd[0] is the read end of pipe
    // fd[1] is the write end of pipe
    pipe(fd);

    if(!fork())
      {
        // first close the write end
        close(1);
        // fd[1] can now take stdout
        dup(fd[1]);
        close(fd[0]);
        execvp(cmds[0], cmds);

      }
     else
      {
        // close read end
        close(0);
        // fd[1] can now take stdin
        dup(fd[0]);
        close(fd[1]);
        execvp(cmds[1], cmds);
      }


}

// starts the program and asks the user to enter input
// loops until the user enters 'exit'
int main()
{
  while(1)
    {
      printf("Enter a command...\n");
      fgets(input, 100, stdin);
      handleCommands(tokenize(input));
    }
}

When I run my shell program, I enter in a command, like ls or cat, and the command executes properly. If I run another command after that one, the command will not execute at all. It could even be the same command as the first one I entered, and it will still not run for the second time. No error messages are given. It just doesn't output what the command calls it to output. I'm currently using execvp, and I believe I am passing in the arguments currently, so I'm not sure where to go from here. Could someone give me some input on why this is happening?

任何你觉得合适的地方(它在主循环中对我有用,尽管我会把设计留给你):

numTokens = 0;

您没有重置在标记化函数中增加的标记数。使用全局变量很容易遗漏像这样的小东西。