首页 文章

c多个管道管道和文件描述符问题

提问于
浏览
0

你好,我对管道的使用有点失落

我必须开发一个类似程序的shell,所以我有一个flex程序已经工作,表达式是这个函数的源

编辑

正如dave指出的那样,我确实声明了功能内部的管道,但我仍然有同样的问题,所以这里是功能的更新我已经卡在它上一段时间已经看起来像我没有关闭管道因为第二个叉总是挂在waitpid上()

但我确实试图关闭主要过程和所有孩子的所有叉子,但第二个叉子仍然悬挂


int execute(Expression *e , int wait, int fdin,int fdout,int fderror){
    int status;
    pid_t childPID;
    int fd;
    int pp[2];

    switch (e->type) {
        case SIMPLE:
            childPID = fork();
            if(childPID >= 0) //fork was successful
            {
                if(childPID == 0) //child process
                {
                    if(fdin != 0){
                        dup2(fdin,0);
                        close(fdin);
                        if(fdin > 2){
                            close(fdin +1); 
                        }
                    }
                    if(fdout != 0){
                        dup2(fdout,1);
                        close(fdout);
                        if(fdout > 3){
                            close(fdout -1);
                        }
                    }
                    if(fderror != 2){
                        dup2(fderror,2);
                        close(fderror);
                    }
                    status = execvp(e->arguments[0], &e->arguments[0]);
                    perror(e->arguments[0]);
                    exit(1);
                }
                else//parent process
                {
                    if(fdin > 2){
                        close(fdin);    
                        close(fdin +1); 
                    }
                    if(fdout > 3){
                        close(fdout);
                        close(fdout -1);    
                    }

                    if(wait == 1){
                        printf("%s\n","going to wait" );
                        waitpid(childPID, &status, 0);
                    }
                    putchar('\n');
                    break;
                }
            }
            else// fork failed 
            {
                perror("fork");
            }
            break;
        case SEQUENCE:
            execute(e->gauche,1,fdin,fdout,fderror);
            execute(e->droite,1,fdin,fdout,fderror);
            break;
        case SEQUENCE_ET:
            execute(e->gauche,0,fdin,fdout,fderror);
            execute(e->droite,1,fdin,fdout,fderror);
            break;
        case SEQUENCE_OU:
            execute(e->gauche,0,fdin,fdout,fderror);
            execute(e->droite,1,fdin,fdout,fderror);
            break;
        case BG:
            execute(e->gauche,0,fdin,fdout,fderror);
            break;
        case PIPE:
            if(pipe(pp) < 0){
                perror("pipe");
                exit(1);
            }
            execute(e->gauche,0,fdin,pp[1],fderror);
            execute(e->droite,1,pp[0],fdout,fderror);
            break;
        case REDIRECTION_I:
            fd = open(e->arguments[0],O_RDONLY, 0666);
            execute(e->gauche,1,fd,fdout,fderror);
            break;
        case REDIRECTION_O:
            fd = open(e->arguments[0],O_CREAT | O_RDWR, 0666);
            execute(e->gauche,1,fdin,fd,fderror);
            break;
        case REDIRECTION_A:
            fd = open(e->arguments[0], O_TRUNC | O_CREAT | O_RDWR, 0666);
            execute(e->gauche,1,fdin,fd,fderror);
            break;
        case REDIRECTION_E:
            fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
            execute(e->gauche,1,fdin,fdout,fd);
            break;
        case REDIRECTION_EO:
            fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
            execute(e->gauche,1,fdin,fd,fd);
            break;
        default:
            return 0;
            break;

    }
    return 0;


}

我的问题是这对于简单的命令很有用

ls | grep a

ls > test

但如果我搞砸了那就完全错了

为例

ls | grep a > test

我得到了终端的输出而不是文件

或者如果我使用

ls | grep a | grep c

管道变得一团糟,我猜我需要更多的管道来做它但我不知道如何在飞行中创建管道

谢谢大家

编辑


刚刚发现在修复管道之后我确实尝试了更大数据的命令,而不是ls我在一个文件上做了猫,所以看起来命令在任何数据到达管道之前停止

2 回答

  • 1

    您正在为所有管道使用全局变量 . 当您创建 ls | grep a 时,您的全局管道工作正常 . 但是当你有多个管道时,你可以将它们用于不同的目的!解决方案是在函数中提取管道创建代码 . 当你需要一个新管道时,在那里创建一个并将正确的文件描述符传递给 execute 的递归调用(这就是你需要 fdinfdout 参数的原因 .

  • 1

    所以我想我修好了

    我的问题是在最后一个fork被激活之前调用wait在这种情况下我添加了标志f来识别最后一个命令并使用等待pid就在最后一个

    这是代码

    int execute(Expression *e , int wait, int fdin,int fdout,int fderror, int lastflag){
        int status;
        pid_t childPID;
        int fd;
        int pp[2];
    
    
        switch (e->type) {
            case SIMPLE:
                childPID = fork();
                if(childPID >= 0) //fork was successful
                {
                    if(childPID == 0) //child process
                    {
                        if(fdin != 0){
                            dup2(fdin,0);
                            close(fdin);
                        }
                        if(fdout != 1){
                            dup2(fdout,1);
                            close(fdout);
                        }
                        if(fderror != 2){
                            dup2(fderror,2);
                            close(fderror);
                        }
                        for(int i = 3; i <= lastfd; i++){
                            close(i);
                        }
    
                        status = execvp(e->arguments[0], &e->arguments[0]);
                        perror(e->arguments[0]);
                        exit(1);
                    }
                    else//parent process
                    {
    
                        if(wait == 1){
                            for(int i = 3; i <= lastfd; i++){
                                close(i);
                            }
                            printf("%s\n","going to wait" );
                            waitpid(childPID, &status, WNOHANG);
                        }
                        putchar('\n');
                        break;
                    }
                }
                else// fork failed 
                {
                    perror("fork");
                }
                break;
            case SEQUENCE:
                execute(e->gauche,1,fdin,fdout,fderror,0);
                execute(e->droite,1,fdin,fdout,fderror,0);
                break;
            case SEQUENCE_ET:
                execute(e->gauche,0,fdin,fdout,fderror,0);
                execute(e->droite,1,fdin,fdout,fderror,0);
                break;
            case SEQUENCE_OU:
                execute(e->gauche,0,fdin,fdout,fderror,0);
                execute(e->droite,1,fdin,fdout,fderror,0);
                break;
            case BG:
                execute(e->gauche,0,fdin,fdout,fderror,0);
                break;
            case PIPE:
                if(pipe(pp) < 0){
                    perror("pipe");
                    exit(1);
                }
                ch_lastfd(pp[1]);
                execute(e->gauche,0,fdin,pp[1],fderror,0);
                if(lastflag == 1){
                    execute(e->droite,1,pp[0],fdout,fderror,0);
                }else{
                    execute(e->droite,0,pp[0],fdout,fderror,0);
                }
                break;
            case REDIRECTION_I:
                fd = open(e->arguments[0],O_RDONLY, 0666);
                ch_lastfd(fd);
                execute(e->gauche,1,fd,fdout,fderror,0);
                break;
            case REDIRECTION_O:
                fd = open(e->arguments[0],O_CREAT | O_RDWR, 0666);
                ch_lastfd(fd);
                execute(e->gauche,1,fdin,fd,fderror,0);
                break;
            case REDIRECTION_A:
                fd = open(e->arguments[0], O_TRUNC | O_CREAT | O_RDWR, 0666);
                ch_lastfd(fd);
                execute(e->gauche,1,fdin,fd,fderror,0);
                break;
            case REDIRECTION_E:
                fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
                ch_lastfd(fd);
                execute(e->gauche,1,fdin,fdout,fd,0);
                break;
            case REDIRECTION_EO:
                fd = open(e->arguments[0], O_CREAT | O_RDWR, 0666);
                ch_lastfd(fd);
                execute(e->gauche,1,fdin,fd,fd,0);
                break;
            default:
                break;
    
        }
        return 0;
    
    
    }
    

    可能不是实现它的最佳方式,所以如果任何人知道如何让它变得更好我会打开提示感谢

相关问题