【问题标题】:c multiple pipes pipes and problems with file descriptorc多个管道管道和文件描述符问题
【发布时间】:2014-11-01 15:03:40
【问题描述】:

你好,我对管道的使用有点迷茫

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

编辑

正如戴夫所说 我确实在函数内声明了管道,但我仍然有同样的问题 所以这里是我已经被困一段时间的功能的更新 看起来我没有正确关闭管道,因为第二个叉子总是挂在 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 

管道变得一团糟,我想我需要更多的管道来做,但我不知道如何即时创建管道

谢谢大家

编辑


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

【问题讨论】:

  • pp在哪里定义?它是做管道的东西,但你没有给我们定义。
  • pp 只是一个 int pp[2] 后跟一个 pipe(pp)

标签: c pipe stdout stdin


【解决方案1】:

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

【讨论】:

  • 刚刚根据您指出的内容进行了编辑,但我仍然得到相同的结果
【解决方案2】:

所以我想我修好了它

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


}

可能不是实现它的最佳方式,所以如果有人知道如何让它变得更好,我愿意提供提示,谢谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-18
    • 1970-01-01
    • 2018-11-29
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多