【问题标题】:minishell created in c not working as expected, pipes related在 c 中创建的 minishell 无法按预期工作,与管道相关
【发布时间】:2017-03-28 23:33:09
【问题描述】:

我在我的操作系统签名中用 c 制作了一个 UNIX minishell。我只需要改进 shell 本身,我们有一个用于实现 yacc 的预制解析器和一个用于实现 lex 的扫描器以及其他文件。 要修改的文件是主可执行文件msh.c。

好吧,当我尝试实现管道安全时,问题就开始了。这是我做的:

int executePipeLine (char*** argvv, int bg, char** filev, int n){
    int i;
    int in = 0;
    pid_t pid;
    int fd[2];

for (i = 0 ; i < n-1 ; i++){

    pipe(fd);
    pid_t pid = fork();


    if (pid == 0){ //child

        if (in != STDIN_FILENO){
            dup2(in, STDIN_FILENO);
            close(in);

        }

        if (fd[1] != STDOUT_FILENO){
            dup2(fd[1], STDOUT_FILENO);
            close(fd[1]);
        }

        execvp(argvv[i][0], argvv[0]);
    }

    else { //parent

        close(fd[1]);
        in = fd[0];
    }


}

if(in != STDIN_FILENO){
    dup2(in, STDIN_FILENO);
    close(in);
}

pid_t lastpid = fork();
if(lastpid == 0){ //child

execvp(argvv[i][0], argvv[0]);


}

if(lastpid == -1){

    perror("no se pudo crear el hijo\n");
    exit(-1);

}
else { //parent

    /* not bg*/
    if(!bg ) {
    int status;
    while (wait(&status) != lastpid); /* wait the child. */
    }

    else {
    /*bg mode*/
        printf("pid del proceso last: %d\n", lastpid);

    }

    return 0;
}

}//end  executePipeLine

这似乎工作正常。在 main 中,我们有一个名为 gain_order() 的外部函数;返回命令数 + 1 并将其保存到 ret。如果 ret 为 1 则继续提示,如果为 0 表示 EOF(Control + D 键绑定)结束 shell,如果为 >1 则执行命令。

给你:

int main(void)
{
    char ***argvv;
    int command_counter;
    int num_commands;
    int args_counter;
    char *filev[3];
    int bg;
    int ret;
    int reset = 0;
    setbuf(stdout, NULL);           /* Unbuffered */
    setbuf(stdin, NULL);

while (1)
{
    fprintf(stderr, "%s", "msh> "); /* Prompt */

    ret = obtain_order(&argvv, filev, &bg);

    printf("ret: %d\n", ret);
    if (ret == 0) break;        /* EOF */
    if (ret == -1) continue;    /* Syntax error */
    num_commands = ret - 1;     /* Line */
    if (num_commands == 0) continue;    /* Empty line */

    if(num_commands > 1){

        executePipeLine(argvv, bg, filev, num_commands);

    }
    else if (num_commands == 1){
        executeCommand(argvv, bg, filev);

    }

} //fin while

return 0;

} //end main

一个简单的命令就可以正常工作。问题是当我尝试执行管道时。它显示了一个很好的结果,但我不知道我们,在下一次迭代之后 ret 总是为 0,所以每次我尝试执行管道时,它都会工作但关闭 shell 进程,并且必须再次执行它而不是继续提示。

你知道这里有什么问题吗?

我希望你能理解我,我的英语并不完美。谢谢

【问题讨论】:

    标签: c shell unix pipe


    【解决方案1】:

    在父进程(即您的 mini-shell)中,您是 duping 标准输入:

    ...
    else { //parent
        close(fd[1]);
        in = fd[0];
    }
    
    ...
    
    if(in != STDIN_FILENO){
        dup2(in, STDIN_FILENO);
        close(in);
    }
    

    当您的管道终止时,子进程已死,管道不再可读 => 标准输入被视为已关闭。当您稍后在主循环中调用 obtain_order 时,它会返回 0 (EOF) 并且您的程序会退出。

    【讨论】:

    • 所以你的意思是我必须删除 dup 行?我应该怎么做?
    • 不确定。如果您需要dup,最简单的解决方案似乎是保存和恢复(使用dup/dup2)原始标准输入。您还可以在子 shell(分叉进程)中执行整个管道。
    • 谢谢老兄!我终于在子进程中执行了管道。完美运行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    • 2012-11-18
    • 2016-04-24
    • 2020-01-01
    • 2019-12-13
    • 1970-01-01
    相关资源
    最近更新 更多