繁体   English   中英

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

[英]c multiple pipes pipes and problems with file descriptor

你好,我对使用管道有些迷惑

我必须开发一个类似shell的程序,所以我已经有一个flex程序正在工作,并且表达式可以提供给该函数

编辑

正如dave指出的那样,我确实在函数内部声明了管道,但是我仍然遇到相同的问题,所以这是对函数的更新,我被卡在上面已经有一段时间了,好像我没有适当地关闭管道,因为第二个叉子总是挂在waitpid()上

但是我确实试图关闭主进程上的所有fork和所有子进程,但是第二个fork仍然挂着


   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,而不是我在工作正常的文件上执行了cat命令,因此看起来该命令在任何数据到达管道之前就停止了

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

所以我想我把它修好了

我的问题是在这种情况下,在启动最后一个fork之前调用了等待,在这种情况下,我确实添加了标志f来标识最后一个命令,并在最后一个命令上使用wait 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;


}

可能不是实现它的最佳方法,所以如果有人有任何想法如何使其变得更好,我欢迎您提出建议,谢谢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM