2017-03-26 35 views
3

我目前正在写我自己的壳实施C.我的理解后面的管道和重定向FDS原则。然而,一些具体的管道行为引起了我的注意:管在自己的壳实现链接

  • cat | ls(或任何不从stdin读取的命令作为管道的最终元素)。

在这种情况下,shell中会发生什么情况是ls执行并且猫在退出之前请求单行(由我猜测得到的SIGPIPE导致)。我曾试图按照本教程以更好地了解多个管道背后的原则:http://web.cse.ohio-state.edu/~mamrak.1/CIS762/pipes_lab_notes.html

下面是一些代码,我已经写了,试图复制我要找的行为:

char *cmd1[] = {"/bin/cat", NULL}; 
char *cmd2[] = {"/bin/ls", NULL}; 
int  pdes[2]; 
pid_t child; 

if (!(child = fork())) 
{ 
    pipe(pdes); 
    if (!fork()) 
    { 
     close(pdes[0]); 
     dup2(pdes[1], STDOUT_FILENO); 
     /* cat command gets executed here */ 
     execvp(cmd1[0], cmd1); 
    } 
    else 
    { 
     close(pdes[1]); 
     dup2(pdes[0], STDIN_FILENO); 
     /* ls command gets executed here */ 
     execvp(cmd2[0], cmd2); 
    } 
} 
wait(NULL); 

我所知道的该实现的安全缺陷,但这仅仅用于测试。这个代码的问题是,我知道每当ls被执行时,它就会退出,然后cat以某种方式在后台运行(并且在我的情况下失败,因为它会在我的程序退出时尝试在zsh提示符下读取)。我无法找到解决方案,使它像应该那样工作。因为如果我一个一个地等待命令,那么这样的命令如cat/dev/random |如果任何人有这个问题的解决方案,或者至少提供一些指导,将不胜感激头〜10会永远运行下去......

+0

我不感兴趣的命令任何用处。我只是在复制bash的行为,这是有兴趣的:首先显示LS的输出,并运行猫将只需要一条线,然后(即提示一行的用户) –

+2

在你的榜样,'cat'成为同时'孙子ls'是一个孩子。 'wait'只等待'ls'。你应该让'猫'和'ls'直接的孩子,然后等待两者。 –

+0

@thatotherguy确实,我刚刚尝试过您的解决方案,它绝对有效。而且这个解决方案似乎接近了我链接的教程中提供的第一个想法。但是,如果我想要扩展多个命令,会发生什么?这就是为什么第二个实现看起来更有趣的原因!我应该可以有很多链接命令。有了这个解决方案,看起来我必须事先知道我有多少个命令来准备管道和叉子没有? –

回答

0

考虑从@thatotherguy这里的评论后,我发现在我的代码实现的解决方案。请记住,电话应检查错误,但这个版本,就是要尽可能简单。额外退出调用也是我的一些内置命令所必需的。

void exec_pipe(t_ast *tree, t_sh *sh) 
{ 
    int  pdes[2]; 
    int  status; 
    pid_t child_right; 
    pid_t child_left; 

    pipe(pdes); 
    if (!(child_left = fork())) 
    { 
     close(pdes[READ_END]); 
     dup2(pdes[WRITE_END], STDOUT_FILENO); 
     /* Execute command to the left of the tree */ 
     exit(execute_cmd(tree->left, sh)); 
    } 
    if (!(child_right = fork())) 
    { 
     close(pdes[WRITE_END]); 
     dup2(pdes[READ_END], STDIN_FILENO); 
     /* Recursive call or execution of last command */ 
     if (tree->right->type == PIPE_NODE) 
      exec_pipe(tree->right, sh); 
     else 
      exit(execute_cmd(tree->right, sh)); 
    } 
    /* Should not forget to close both ends of the pipe */ 
    close(pdes[WRITE_END]); 
    close(pdes[READ_END]); 
    wait(NULL); 
    waitpid(child_right, &status, 0); 
    exit(get_status(status)); 
} 

我与我发布的原始链接以及处理链接管道的不同方式相混淆。从链接到文件下面贴我原来的问题的POSIX(http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_02)看来:

如果管道是不是在后台(见异步列表),外壳必须等待指定的最后一个命令管道完成,也可能等待所有命令完成。

因此两种行为都被接受:等待最后的命令或等待所有的行为。我选择实施第二种行为来坚持bash/zsh的行为。