2

尝试使用一些基本功能实现我自己的 linux shell,当然,在实现管道时会出现问题。更具体地说,管道在大多数情况下都有效,尽管它似乎放弃了最后一个参数。例如,如果我要运行命令

ps ax | grep ps

grep 命令后的 ps 被删除到我的 shell 中。因此,不要像使用典型的 Linux shell 那样输出它

339 ?        S      0:00 upstart-udev-bridge --daemon
497 ?        Ss     0:00 /usr/sbin/cupsd -F
503 ?        S<     0:00 [kpsmoused]
720 ?        S      0:00 upstart-socket-bridge --daemon
5541 pts/0    R+     0:00 ps ax
5542 pts/0    S+     0:00 grep --colour=auto ps

你得到这个

339 ?        S      0:00 upstart-udev-bridge --daemon
497 ?        Ss     0:00 /usr/sbin/cupsd -F
503 ?        S<     0:00 [kpsmoused]
720 ?        S      0:00 upstart-socket-bridge --daemon
5557 pts/0    R+     0:00 ps ax

在这种情况下,您不是在搜索匹配的模式 ps。

管道的功能运行如下

void mypipes(char* args[], int nargs)
{
  pid_t pid;
  int fd[2];

  char* cmdargs[nargs - 2];
  char* cmdargs2[nargs - 2];


  int i;
  int t = 0;
  int count = 0;

  for(i = 0; i < nargs; i++)
  {
if(!strcmp(args[i], "|"))
{
    //dont put into array
    t = 1;
}
else if(t == 0)
{
    cmdargs[i] = args[i];
    count++;
}
else if(t == 1)
{
    cmdargs2[i - 3] = args[i];
}
  }


  if(count == 2)
  {
  pipe(fd);
  pid = fork();

  if(pid == -1)
  { 
    perror("unable to fork");
    exit(1);
  }
  if(pid > 0)
  {
    wait(&pid);
    close(fd[1]);
    close(0);
    dup2(fd[0],0);
    execlp(cmdargs2[0], cmdargs2[0], cmdargs2[1], NULL);
  }
  if(pid == 0)
  {
    close(fd[0]);
    close(1);
    dup2(fd[1],1);
    execlp(cmdargs[0], cmdargs[0], cmdargs[1], NULL);
  }
  }

  if(count == 1)
  {
  pipe(fd);
  pid = fork();

  if(pid == -1)
  { 
    perror("unable to fork");
    exit(1);
  }
  if(pid > 0)
  {
    wait(&pid);
    close(fd[1]);
    close(0);
    dup2(fd[0],0);
    execlp(cmdargs2[0], cmdargs2[1], NULL);
  }
  if(pid == 0)
  {
    close(fd[0]);
    close(1);
    dup2(fd[1],1);
    execlp(cmdargs[0], cmdargs[1], NULL);
  }

  }

}

我检查了管道之后的所有变量是否仍在第二组参数中,它们不是主要问题,而是我正在执行实际管道的地方,它没有读到最后.

提前感谢您提供有关此处可能出现问题的任何提示。

4

1 回答 1

1

首先,除非我遗漏了什么,否则您的两个示例输出看起来都在工作:它们都只列出了其中包含“ps”的行。(如果它真的在运行,ps ax | grep那么grep会抱怨使用情况)。我可以在输出中看到的唯一区别是第二个没有列出进程本身,但是如果在启动之前已经完成了进程列表的抓取grep,这很容易发生。psgrep

其次,您的使用wait(&pid)很奇怪——因为它在进程中,它将等待子进程的任何子进程退出。因为没有,它会返回ECHILD(如果有,它会pid用孙子的退出状态覆盖)。

第三,您使用t,cmdargscmdargs2count决定进行哪个execlp调用只有在它的形式是有效的cmd1 arg1 | cmd2 arg2- 几乎任何其他组合都不起作用。几点:

  • 而不是[i -3]在管道之后保存参数,您需要记住您在哪个位置看到了管道(例如,当您找到管道以及在它之后保存参数时t=1使用而不是)。t=i+1cmdargs2[i-t]
  • 您需要查看execvp()函数调用的版本,以便可以传入参数数组(记住在命令行中的所有元素之后添加一个 NULL 元素)。
于 2013-07-17T20:42:49.670 回答