我的简单 UNIX shell 中的重定向和管道传输问题

发布于 2024-10-04 16:32:46 字数 4403 浏览 5 评论 0原文

编辑:我无法让某些缩进正常工作,但代码完整并正确阻止。对不起。

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

我几乎已经让它工作了,但由于某种原因,它无法正确处理 program1 | 形式的命令。程序2 - 文件。例如,cat <文件1.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;
  }
}

EDIT: I can't get some of the indents to work correctly, but the code is complete and blocked correctly. Sorry.

For a class assignment I've had to implement part of a simple UNIX shell. It must support redirection, piping, and backgrounding. I was provided with a parser that populates a struct called Command_line (I'll include the struct prototype below). My job is to write a function that processes these Command_lines (handles redirection, backgrounding, piping, and executes programs).

I've almost got it working but for some reason it doesn't properly handle commands of the form program1 | program2 - file. For example, cat < file1.in | cat - file2.in. The problem doesn't seem to be in the redirection as I've written test programs to put in front of the pipe that do not require redirection but still cause the same problem. The pipelining does work in most cases; it's just these programs with "-" as an argument that cause problems.

When I run one of these problematic command lines, the output from the first program is printed and the process hangs up (I have to manually suspend and kill it). It does not give the user a prompt afterwards or react to input (aside from ctrl + z which I use to suspend the process).

Any advice on how to get this working would be much appreciated.

Here's the struct:

/* 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;

And my code, that processes one of these structs (I've left out the #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;
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

苦笑流年记忆 2024-10-11 16:32:47

run_proc() 内,在 /*close pipelineends*/ 循环中,
应该是

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]);
    }

Within the run_proc(), in the /*close pipe ends*/ loop,
it should be

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]);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文