【问题标题】:Having trouble with implementing multiple pipes in C在 C 中实现多个管道时遇到问题
【发布时间】:2014-03-28 14:12:54
【问题描述】:

我正在尝试在 C 中实现一些 Shell 命令,但管道给我带来了一些麻烦(我踢掉了大部分代码,所以你们可以编译它 - 如果需要)

我的工作与他在 2011 年 old post987654321@ 发布的 Mkabs 解决方案非常接近

经历过之后,我以为我把它搞砸了,但它不起作用。

简单示例:>> **ls |排序 -r **

  • 第一个孩子使用第一个管道1 作为标准输出{1}
  • 第二个孩子使用第一个管道[0] 作为标准输入{0}

但是两个 exec() 都失败了:ENOENT,没有这样的文件或目录
不管我是从 userInput 读取命令还是硬编码给定的字符串,它总是会失败。

因此错误必须在 ExecutePipe() fkt 中,无需通过其余部分。

    #define _POSIX_C_SOURCE 1
    #include <alloca.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/times.h>
    #include <sys/wait.h>


    typedef char* string;
    static int keepRunning = 1;
    char inputBuffer[512];
    string satz[256];
    int j,comCount, modePipe,mode;

    void Tokens(string);
    void ExecutePipe(void);
    int ScanInput(void);


    void Tokens(string token){
        int len;
        char* ptrC;
        j=0;
        satz[j] = strtok (inputBuffer, token); 
        while (satz[j] != NULL)
        {
            j++;
            satz[j] = strtok (NULL, token); 
        }
        comCount =j;  


        /*REPLACE NEWLINE of LAST COMMAND */
        len =strlen(satz[j-1]);
        ptrC = satz[j-1];
        for (j=0;j<len;j++){
            if (*ptrC == '\n'){
                *ptrC = '\0';
            }
            ptrC++;
        }
    }

    void ExecutePipe(void){
        int* ptrPipe;
        int i,k=0, numPipes;
        pid_t pid, status;
        int  stdin_dupfd,stdout_dupfd;
        string* ptrSatz = satz;
        modePipe=1;
        Tokens("|");
        stdin_dupfd = dup(0);
        stdout_dupfd = dup(1);

        numPipes = comCount-1;

        ptrPipe = (int*) alloca(numPipes*2);

        for(i = 0; i < numPipes; i++){
            if(pipe(ptrPipe + i*2) < 0) {
                printf("Error: pipe(%d)\n",i);
                return;
            }
        }

        while(k<comCount) {
            pid = fork();
            if(pid < 0){
                fprintf(stderr,"Error: PID.%d\n", pid);
                exit(9);
            }
            else if(pid == 0) {  /* child gets input from the previous command*/
                if(k > 0){      /*if not first command*/
                    if(dup2(ptrPipe[(k-1) * 2], 1) < 0){ /*ptr[0]. ptr[2], ptr[4], ...*/    
                        fprintf(stderr,"Error: dup2(firstCommand)\n");
                        exit(10);
                    }
                    else fprintf(stderr,"k[%d]:dupe2([%d], 0)\n",k,(k-1)*2);
                }
                if(k != (comCount-1) ){ /*if not last command*/
                    if(dup2(ptrPipe[k * 2 + 1], 1) < 0){ /*ptr[1]. ptr[3], ptr[5], ...*/    
                        fprintf(stderr,"Error: dup2(notLastCommand)\n");
                        exit(11);
                    }
                    else fprintf(stderr,"k[%d]:dupe2([%d], 1)\n",k,k*2+1);
                }
                for(i = 0; i < 2*numPipes; i++){
                    close(ptrPipe[i]);
                }
                if( execlp(*ptrSatz, *ptrSatz) < 0 ){   /*  */
                    fprintf(stderr,"Error: ");
                    fprintf(stderr,"exec(%s)(%d)\n", *ptrSatz, errno);
                    exit(12);
                }
            }

            fprintf(stderr,"[%d]: %s\n", k,*ptrSatz);
            ptrSatz++;
            k++;
        } 

        for(i = 0; i < 2 * numPipes; i++){
            close(ptrPipe[i]);
            /*printf("loop %d of %d\n ",i, 2*numPipes);*/
        }
        for(i = 0; i < numPipes + 1; i++){
            wait(&status);
        }

        dup2(stdin_dupfd, 0);
        dup2(stdout_dupfd, 1);
        close(stdin_dupfd);     
        close(stdout_dupfd);    

        inputBuffer[0] = '\0';
        modePipe=0;
    }   

    int main (void)
    {
        while (keepRunning){
            printf(">> ");
            fgets(inputBuffer, 512, stdin);   /* input buffer, max.Input(char), whereFrom?*/
            mode = ScanInput(); /*checks inputBuffer on keywords, returns int 1-13*/
            /*printf(">> mode:%d\n", mode);*/
            switch(mode){
                case 11 :
                    ExecutePipe();
                    break; 
            }
        }
        return 0;
    }

    int ScanInput(void){
        char * pch;

        pch = strstr (inputBuffer," | ");
        if (pch != NULL)
            return 11;
        else 
            return 1;
    }

谢谢!

【问题讨论】:

    标签: c shell unix


    【解决方案1】:

    exec 只能调用单个二进制文件。你在这里给了一个shell命令。使用system() 函数,您也可以调用shell 命令,但它之所以有效,只是因为它调用bash 来解释它。

    最简单的解决方案是通过systemexit-ing 调用此行,就像

    exec("complex|shell|command >&3");
    

    需要改成

    system("complex|shell|command >&3");
    exit(0);
    

    【讨论】:

    • 每个 Child 只调用一个二进制 + 参数。 [1]exec(ls) [2]exec(sort -r).
    【解决方案2】:

    我的 dup2 迭代变量出错。 预期的行为是:

    dup2 - notLast      notFirst
           1,1          [first]
           3,1          0,0
           5,1          2,0
           7,1          4,0
           ..           ..
    

    并且 notLast 部分错误地递增了......

    修复后,运行顺利

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多