我的简单UNIX shell中的重定向和流水线问题

时间:2010-11-29 01:05:22

标签: shell background pipe redirect pipeline

编辑:我无法使某些缩进正常工作,但代码已完成并正确阻止。遗憾。

对于类赋值,我必须实现一个简单的UNIX shell的一部分。它必须支持重定向,管道和背景。我提供了一个解析器来填充一个名为Command_line的结构(我将在下面包含结构原型)。我的工作是编写一个处理这些Command_lines的函数(处理重定向,后台处理,管道和执行程序)。

我几乎让它工作但由于某种原因它无法正确处理 program1 |形式的命令program2 - 文件。例如,cat< file1.in | cat - file2.in。这个问题似乎没有在重定向中,因为我已经编写了测试程序放在管道前面,不需要重定向,但仍然会导致同样的问题。流水线在大多数情况下都有效;只是这些程序以“ - ”作为引发问题的论据。

当我运行其中一个有问题的命令行时,会打印第一个程序的输出并且进程挂起(我必须手动挂起并终止它)。它之后不会给用户提示或对输入做出反应(除了我用来暂停进程的ctrl + z)。

非常感谢任何关于如何使这项工作的建议。

这是结构:

/* This is the structure that holds the information about a parsed
 * command line.  The argvs array is an array of string vectors; in
 * other words, for some int i, argvs[i] is an array of strings.
 * You should be able to use argvs[i] in calls to one of the execv*()
 * functions.
 */
typedef struct {
  char *argvs[MAX_PROGS + 1][MAX_ARGS + 1];
  int num_progs;  /* Number of argument vectors; if > 1, piping is requested */
  char *infile;   /* Name of stdin redirect file; NULL if no redirection */
  char *outfile;  /* Name of stdout redirect file; NULL if no redirection */
  int append;     /* Is output redirection appending? */
  int bg;         /* Put command into background? */
} Command_line;

我的代码处理其中一个结构(我遗漏了#includes)。

pid_t runproc(int fd[][2], int num, Command_line *cmd);

void execute_command_line(Command_line *cmd) {
  int n;
  int temp_pipe[2];
  int fd[MAX_PROGS-1][2];
  pid_t pids[MAX_PROGS];

  /* Clears pipes (sets all values to -1*/
  for(n = 0; n < cmd->num_progs; n++){
    fd[n][0] = -1;
    fd[n][1] = -1;
  }

  /*Uses temp_pipe to connect write end of nth pipe to read end of (n+1)th 
    pipe*/
  for(n = 0; n < cmd->num_progs - 1; n++){
    pipe(temp_pipe);
    fd[n][1] = temp_pipe[1];
    fd[n+1][0] = temp_pipe[0];
  }

  /*If input file redirection is occuring, redirects read end of first pipe to
    file*/
  if(cmd->infile){
    fd[0][0] = open(cmd->infile, O_RDONLY);
    if(fd[0][0] < 0){
      printf("Error executing command\n");
      exit(1);
    }
  }

  /*If output file redirection is occurring, redirects write end of last pipe to
    file. Sets append option according to append field of command*/
  if(cmd->outfile){
    if(cmd->append){
      fd[cmd->num_progs - 1][1] = open(cmd->outfile, O_APPEND | O_WRONLY);
      if(fd[cmd->num_progs - 1][1] < 0){
printf("Error executing command\n");
exit(1);
      }
    }else{
      fd[cmd->num_progs - 1][1] = open(cmd->outfile, O_WRONLY);
      if(fd[cmd->num_progs - 1][1] < 0){
 printf("Error executing command\n");
 exit(1);
      }
    }
  }

  /*Runs runproc for every program in pipe, stores return values (pids of
    children) in array*/
  for(n = 0; n < cmd->num_progs; n++){
    pids[n] = runproc(fd, n, cmd);
  }

  /*Closes all pipes*/
  for(n = 0; n < cmd->num_progs; n++){
    if(fd[n][0] >= 0) close(fd[n][0]);
    if(fd[n][1] >= 0) close(fd[n][1]);
  }

  /*Waits for all children*/
  for(n = 0; n < cmd->num_progs; n++){
    wait(NULL);
  }

}

pid_t runproc(int fd[][2], int num, Command_line *cmd){
  pid_t pid;
  int n;
  int frk_chk;

  pid = fork();
  if(pid < 0){
    printf("Error executing command\n");
    exit(1);
  }else if (!pid){ /*Child code*/
    /*Redirects stdin/stdout of process to read/write end of corresponding
      pipe*/
    if(fd[num][0] >= 0) dup2(fd[num][0], STDIN_FILENO);
    if(fd[num][1] >= 0) dup2(fd[num][1], STDOUT_FILENO);

    /*Closes pipe ends*/
    for(n=0; n < cmd->num_progs - 1; n++){
      if(fd[num][0] >= 0) close(fd[num][0]);
      if(fd[num][1] >= 0) close(fd[num][1]);
    }

    /*If backgrounding: forks, parent exits, child executes program. 
      If not backgrounding: program just executes*/
    if(cmd->bg){
      if((frk_chk = fork()) < 0){
 printf("Error executing command\n");
 exit(1);
      }else if(frk_chk){
 exit(0);
      }else{
 if(!(cmd->infile) && num == 0) close(STDIN_FILENO);
 execvp(cmd->argvs[num][0], cmd->argvs[num]);
      }
    }else{
      if(!num){
 dup2(fd[0][1], STDOUT_FILENO);
      }
      execvp(cmd->argvs[num][0], cmd->argvs[num]);
    }
    printf("Error executing command\n");
    exit(1);
  }else{ /*Parent code*/
    /*Returns pid of child, used for reaping loop*/
    return pid;
  }
}

1 个答案:

答案 0 :(得分:0)

run_proc()循环中的/*close pipe ends*/内, 它应该是

for(n=0; n < cmd->num_progs - 1; n++)
   {
      if(fd[n][0] >= 0) close(fd[n][0]);
      if(fd[n][1] >= 0) close(fd[n][1]);
    }