2016-11-20 31 views
-2

我想在c中编写一个简单的shell。现在我试图让管道工作。我有一个结构c我敢送入这个功能,它包含存储管文件描述符pipfd的位置,并且包含了每个命令c->type的结束标记信息(这可以是| || & & &等)。 CommandPrev只是跟踪最后一个命令,所以我可以看到命令之前是否有管道标签。为什么我的管道不能互相交谈?

我完成这项工作后,我给孩子的PID(返回值)waitpid伺候我execvp

称为当我运行的命令,例如echo foo | echo bar我得到bar作为输出完全一样的命令我期望,一切都很好。我的问题是,当我尝试运行任何实际上使用来自管道前半部分的输入的命令时,一切都会卡住。如果我运行类似echo foo | wc -c的东西,我不会得到任何输出,它会永远挂起。

我可以看到这个功能对这些类型的命令完成,因为我打印当它返回。发生的事情是,我用execvp调用的命令从来没有发生,所以我的waitpid永远等待。

我认为不知我的我管的两端之间的连接断开。任何一件事都不会被写入,或者它们永远不会被读取,或者管道的接收端从未意识到写入方已经完成,并且只是等待着永远。我立即在所有管道上关闭,所以我倾向于怀疑它的最后一个......但我真的不知道如何去测试这三种情况中的任何一种。

这是我的代码:

pid_t start_command(command* c, pid_t pgid) { 
    (void) pgid; 

    // If its a pipe token, create a shared pipe descriptor 
    if (c->type == TOKEN_PIPE){ 
     pipe(c->pipefd); 
    } 

    // Fork a child process, run the command using `execvp` 
    pid_t child = fork(); 
    if (child == 0) { 
     // writing side of the pipe 
     if (c->type == TOKEN_PIPE){ 
      dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO); 
      close(c->pipefd); 
     } 
     // receiving side of the pipe 
     else if (commandPrev->type == TOKEN_PIPE){ 
      dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO); 
      close(commandPrev->pipefd); 
     } 

     // run the command 
     if (execvp(c->argv[0], c->argv) == -1) { 
      // fork failed 
      exit(-1); 
     } 
    } 
    else{ 
     // clean up, clean up, everybody, everywhere 
     if (commandPrev->type == TOKEN_PIPE){ 
      close(commandPrev->pipefd); 
     } 
    } 
    printf("return %i\n", getpid()); 
    return child; 
} 

谢谢!

+0

检查您的系统调用错误,它们不会自动打印。 'close(c-> pipefd);'似乎试图关闭一个数组。 –

+0

对于壳牌规格和语言的知识将帮助人们回答的问题,请使用'shell'标签。人们为学校编写玩具壳这一点非常非常少见。 –

+0

@CharlesDuffy我的坏!我不知道,对不起 – Twiigs

回答

0

正如其他评论者说,你看起来就像你试图关闭一个阵列。 像这样的东西应该更好地工作:

// writing side of the pipe 
if (c->type == TOKEN_PIPE){ 
    close(c->pipefd[READ_SIDE]); 
    dup2(c->pipefd[WRITE_SIDE], STDOUT_FILENO); 
    close(c->pipefd[WRITE_SIDE]); 
} 
// receiving side of the pipe 
if (commandPrev->type == TOKEN_PIPE){ 
    close(commandPrev->pipefd[WRITE_SIDE]); 
    dup2(commandPrev->pipefd[READ_SIDE], STDIN_FILENO); 
    close(commandPrev->pipefd[READ_SIDE]); 
} 

或者,也可以在父waitpid函数调用后关闭该管道的有效侧。像这样:

waitpid(child, &status, 0); 

if (commandPrev->type == TOKEN_PIPE){ 
    close(commandPrev->pipefd[READ_SIDE]); 
} 
if (c->type == TOKEN_PIPE){ 
    close(c->pipefd[WRITE_SIDE]); 
} 
相关问题