在用户创建的Shell中实现重定向无法正常工作

时间:2014-03-28 15:59:58

标签: c linux bash shell pipe

我正在尝试使用重定向和管道创建类似于bash的shell。

在我的main()中,我调用解析器,然后调用下面的函数。我遇到的问题是,当我运行我的shell时,它正确地输出到终端,但是在使用>1>或{{{}时,它没有正确输出到文件1}}。

例如,如果我打电话:

2>

我最终收到了:

pwd > foo5.txt

在我写的文本文件中,我写的不是> foo5.txt (对于">" /" 1>")或stdout(对于我想要实现的" 2>")。

这是我的代码,用于分叉和创建子进程:

stderr

更新:现在我的代码无法识别命令,并且打印的参数(用于错误检查)显示为:

pid_t create_process(char *part, int const pipes[][2], int pipenum)
{
  pid_t pid;         // Initialize variables/pointers/arrays.
  char *args[64];
  int argc=0, n;
  char *arg=strtok(part, " \t");
  //char const **filename = args;


  while(arg != NULL)
    {
      args[argc++]=arg;
      arg=strtok(NULL, " \t");
    }

  args[argc++]=NULL;

  pid = fork();     // Create Fork.

  if(pid == 0)
  {
  int m;

  if(pipes[pipenum][STDIN_FILENO] >= 0)
    dup2(pipes[pipenum][STDIN_FILENO], STDIN_FILENO); // FD 0.

  if(pipes[pipenum][STDOUT_FILENO] >= 0)
    dup2(pipes[pipenum][STDOUT_FILENO], STDOUT_FILENO); // FD 1.

  // Close all pipes.
  for(m=0; m<64; m++)
    {
      if(pipes[m][STDIN_FILENO] >= 0)
        close(pipes[m][STDIN_FILENO]);
      if(pipes[m][STDOUT_FILENO] >= 0)
        close(pipes[m][STDOUT_FILENO]);
    }

  char *filename;
  char *newargs[64];
  newargs[63] = NULL;
  int i = 0;
  int j = 0;
  for(i = 0; i<64; i++)
  {
    if (args[i] == ">")
      {
        i++;
        if (args[i] != NULL)
          {
            filename = args[i];
            int redir = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
            dup2(redir, 1);
            close(redir);
          }
      }
    else if (args[i] == "2>")
      {
        i++;
        if (args[i] != NULL)
          {
            filename = args[i];
            int redir = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
            dup2(redir, 2);
            close(redir);
          }
      }

   else if (args[i] == "2>")
      {
        i++;
        if (args[i] != NULL)
          {
            filename = args[i];
            int redir = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
            dup2(redir, 2);
            close(redir);
          }
      }
    else if (args[i] == 0)
      {
        break;
      }
    else
      {
        newargs[j] = args[i];
        j++;
        cout<<"The arg is: " << newargs[j] <<endl;
      }
  }

    execvp(newargs[0], newargs);
    fprintf(stderr, "Command not found.\n");
    exit(255);

  }

else if(pid < 0)
{ // Error checking.
  fprintf(stderr, "Fork Failed\n");
}

return(pid);
}

1 个答案:

答案 0 :(得分:0)

我在这里看到一些问题:

首先,你有for循环,你在那里扫描重定向语法的命令参数(如果(strcmp(args [i],“&gt;”)== 0)等等 - 但是如果条件为真(意思是你找到了一个重定向字符)你总是打开args [2],而不是args [i + 1]。

第二个(这就是重定向语法被传递给您作为命令参数运行的命令的原因) - 一旦检测到重定向语法,就不会从参数列表中删除重定向运算符或目标文件名您传递给execvp()。

例如,如果args [] = {“echo”,“a”,“&gt;”,“logfile”,0},您的代码会检测到将输出发送到名为“logfile”的新文件的请求,正确地重定向FD,但它仍然将这三个参数[“a”,“&gt;”,“logfile”]传递给命令。

第三 - 在你的循环中,你在每个条件语句的末尾调用execvp() - 意味着在启动新进程之前你没有到达参数处理的末尾。您需要处理shell语法的所有命令参数,然后执行命令。

要解决arg处理的各种问题,最有效的解决方案可能是在处理用户提供的原始列表时构建新的参数列表。例如(为了简洁,使用== b作为字符串相等测试)

if (args[i] == ">")
{
   i++; //skip the arg
   if (args[i]) {  // check we haven't hit the end of the arg list
      filename = args[i];
      // then open the file, dup it to stdout or whatever, etc...
}
else if (args[i] == "<") // repeat for other redirection syntax...
else {    // Finally, handle the case where we didn't identify any shell syntax:
   newargs[j] = args[i]; // Copy the arg to the new list, since it isn't "special"
   j++;  // Size of newargs[] has been increased
}

请注意,这仍然无法解决“&gt;”周围没有空格的问题字符:“echo foo&gt;文件”将只打印“foo&gt;文件”...在这种情况下,语法处理会变得复杂一些,因为您必须考虑引用规则和转义字符才能正确处理参数。 / p>