C-单壳管道的实施在终端中不断被挂起

C-单壳管道的实施在终端中不断被挂起,c,linux,shell,pipe,implementation,C,Linux,Shell,Pipe,Implementation,我一直在尝试在shell程序中实现管道结构,如果我执行简单的命令,比如hello | rev,它就会工作 但当我尝试执行head-c 1000000/dev/uradom | wc-c时,它挂起了 忽略引用 我的实施是: int fd[2]; pipe(fd); // IN CHILD // Piping for the first command if (isPipe

我一直在尝试在shell程序中实现管道结构,如果我执行简单的命令,比如hello | rev,它就会工作

但当我尝试执行head-c 1000000/dev/uradom | wc-c时,它挂起了 忽略引用

我的实施是:

             int fd[2];
             pipe(fd);
            // IN CHILD 
           // Piping for the first command
              if (isPiped && (e == list_begin(&p->commands))) 
               {

                  close(fd[0]);
                  dup2(fd[1], 1);
                  close(fd[1]);

               }

               // Last command in the pipe
               else if (isPiped && (list_next(e) ==   list_tail(&p->commands))) 
               {

                  close(fd[1]);
                  dup2(fd[0], 0);
                  close(fd[0]);

               }

      // IN PARENT
     if (isPiped && (e == list_begin(&p->commands))) 
           {
             close(fd[1]);
           }

           else if (isPiped && (list_next(e) == list_tail(&p->commands))) 
           {
              close(fd[0]);
           }
我被教导在使用完文件描述符后总是关闭它,我想这就是我正在做的事情——但是我在某个地方发现了一个文件描述符泄漏,我不知道在哪里。我一直在尝试关闭和复制fd的许多组合,但都没有效果

为了进一步给出完整的问题,以下是主要的相关代码:

我的做法是使用列表结构,将每个命令/作业添加到列表中。变量e是列表的一个元素

int main(int ac, char *argv[]) {

int numPipes = list_size(&commands) - 1;
bool isPiped = false;
if (numPipes > 0)
   isPiped = true;

int fd[2];
pipe(fd);

pid_t pid = fork();
// In child
if (pid == 0) 
{
    if (isPiped && (e == list_begin(&p->commands))) 
    {       
      close(fd[0]);
      dup2(fd[1], 1);
      close(fd[1]);              
    }

   // Last command in the pipe
   else if (isPiped && (list_next(e) == list_tail(&p->commands))) 
   {            
    close(fd[1]);
    dup2(fd[0], 0);
    close(fd[0]);             
   }
// command is a struct. I have it set up so that the terminal can read in what the user inputs
execvp(command->argv[0], command->arg);

 }
// In parent
 if (isPiped && (e == list_begin(&p->commands))) 
 {
  close(fd[1]);
 }

 else if (isPiped && (list_next(e) == list_tail(&p->commands))) 
 {
   close(fd[0]);
 }
 int status;
 waitpid(-1, &status, WUNTRACED);
}
这就是我的管道算法的全部内容。其余的只是用于其他内置作业,如前台、后台、kill命令和io重定向。
非常感谢

父进程应在启动两个子进程后关闭管道的两端。如果它不关闭管道的写入端,则从管道读取的子对象将永远不会获得EOF,因此它将永远不会终止。如果它没有关闭管道的读取端,但正在读取的子级在读取所有输入之前终止,则正在写入的子级将永远不会收到错误,并将阻塞,等待父级读取,而父级却不打算读取

因此,家长只需要:

close(fd[0]);
close(fd[1]);

冒着自嘲的风险,你可能会觉得有趣。谢谢你的反馈!我尝试在if-else-if语句中关闭父级中的两个fd,但它将恢复为挂起基本命令,例如:echo hi | rev。我试图在条件语句之外编写它,但它仍然挂起。唯一没有的时候是我把结束语句单独放在条件语句中,然后我们需要一个MCVE或SSCCE-两个名称和链接来表示相同的想法。还有很多其他的事情你可能做错了;我不想费劲去猜是什么。你应该有一个主程序为几个案例设置数据结构echo hi | rev和head-c 1000000/dev/uradom | wc-c工作得很好,尽管在处理这两个方面应该没有区别。是的,我的代码中有很多不相关的东西,我不想麻烦你。我刚刚编辑过。谢谢@user3171597:更新没有帮助-它不可编译。waitpid的WUNTRACED选项相当专业化;你不需要使用它。您可能应该捕获waitpid返回的PID。如果shell有两个直接子对象,则可能需要一个循环。由于代码中只有一个fork,这就好像您的shell通过运行这两个命令而自毁一样。在execvp之后,您可能应该报告一个错误,并且应该明确退出。如果没有能够准确再现您的问题的代码,没有人能够帮助您。@user3171597:我将更新我的报价。只要代码编译得相当干净,我就会看很多。这将比试图一点一滴地从你身上探出相关信息要容易得多。查看我的个人资料。