在c中实现管道但是它不起作用

时间:2015-08-09 05:26:23

标签: c unix pipe fork

我正在尝试使用c语言实现管道。 我正在通过创建子进程

为管道分隔的每个命令执行循环

以下是我的代码:

int main(int argc, char **argv)
{
    char *cmd,*splitcmd;
    int i,j,nargc=0,characters;
    char **cmdArray;
    size_t bufsize = 1024;
    int *pipefd;
    int pipeArrCount;
    pid_t pid,wpid;
    int status = 0;

    int savestdoutfd = dup(fileno(stdout));
    int savestdinfd = dup(fileno(stdin));

    cmd = (char *)malloc(bufsize * sizeof(char));
    characters = getline(&cmd,&bufsize,stdin);
//    printf("%s%d",cmd,characters);
    if(cmd[characters-1]=='\n')
    {
//        printf("in c");
        cmd[characters-1]='\0';
        characters--;
    }

    cmdArray = (char**)malloc(sizeof(char *) * 100);
    splitcmd=strtok(cmd,"|");
//    printf("%s\n",cmd);
    while((splitcmd))
    {
        cmdArray[nargc] = splitcmd;
        if(cmdArray[nargc][(strlen(cmdArray[nargc]))-1]==' ')
            cmdArray[nargc][(strlen(cmdArray[nargc]))-1]='\0';
        printf("%d    %s",nargc,cmdArray[nargc]);
        nargc++;
        splitcmd = strtok(NULL,"|");
    }

    pipefd=(int*)malloc(2*nargc*sizeof(int));
    printf("%d\n",nargc);
    pipeArrCount=2*(nargc-1);
    printf("%d\n",pipeArrCount);
    //exit(0);
    for(i=0;i<pipeArrCount;i)
    {
        printf("making pipe for process %d\n",i);
        pipe(pipefd+i);
        i=i+2;
    }


    //exit(0);
    for(i=0;i<nargc;i)
    {
        printf("parent count %d\n",i);
        if(i==0)
        {
            printf("Creating child %d\n",i);
            // As it is first process we need to make write end of the pipe as stdout.
            if ((pid=fork()) == 0)
            {
                printf("Creating first child %d for command %s\n",i,cmdArray[i]);
                printf("EXECUTING FIRST PROCESS\n");
                printf("Writing in pipe[%d]\n",2*i+1);

                //close(pipefd[0]);

                dup2(pipefd[2*i+1],fileno(stdout));
                //closing all other pipes
                for(j=0;j<(2*nargc);j++)
                {
                    //if(j!=2*i+1)
                        close(pipefd[j]);
                }
                system(cmdArray[i]);
                //dup2(savestdoutfd,fileno(stdout));
                printf("Stdout is again restored\n");
                //printf("pipe [%d] contains %d ",2*i+1,pipefd[2*i+1]);
                exit(0);
            }

        }
        else if(i!=nargc-1)
        {
            if (fork() == 0)
            {
                printf("EXECUTING MIDDLE PROCESS\n");
                printf("Command to execute %s \n",cmdArray[i]);
                printf("Reading from pipe[%d]\n",(2*(i-1)));
                printf("writing on pipe[%d]\n",(2*i)+1);
                dup2(pipefd[(2*(i-1))], 0); //Read end of the previous process pipe as stdin
                dup2(pipefd[(2*i)+1], 1); //Write end of the pipe of current process as stdout
                //closing all other pipes
                for(j=0;j<(2*nargc);j++)
                {
                    //if((j!=(2*(i-1))) && (j!=(2*i)+1))
                        close(pipefd[j]);
                }
                system(cmdArray[i]);
                exit(0);
            }
        }
        else
        {
            if (fork() == 0)
            {
                printf("Creating last child %d for command %s\n",i,cmdArray[i]);
                printf("Reading from pipe[%d]\n",(2*(i-1)));

                //close(pipefd[1]);

                dup2(pipefd[(2*(i-1))],fileno(stdin)); //Read from the end of the previous process pipe as stdin
                //printf("EXECUTING LAST PROCESS\n");
                //closing all other pipes
                for(i=0;j<(2*nargc);j++)
                {
                    //if(j!=(2*(i-1)))
                        close(pipefd[j]);
                }
                dup2(savestdoutfd,fileno(stdout));
                close(savestdoutfd);
                system(cmdArray[i]);
                dup2(savestdinfd,fileno(stdin));
                close(savestdinfd);
                exit(0);
            }
        }
        i=i+1;
        sleep(1);
    }
    while ((wpid = wait(&status)) > 0);
}

没有得到第二个命令的任何输出 现在我正试图执行这个&#39; A | B&#39;命令类型 如果执行代码

,则必须在命令和管道之间留出空格

2 个答案:

答案 0 :(得分:0)

我执行了你的代码。它适用于单管道,如:

ls | grep "a" and ls | wc.

它不适用于像ls | grep "a" | wc这样的双重管道。 错误是错误的文件描述符

我没有调试这个错误,似乎在&#34中有一些错误处理文件描述符;否则如果&#34;条款。你问题的任何方式都不适用于像A | B这样的单一管道。但确实如此。

希望这有帮助。

答案 1 :(得分:0)

你没有那么正确的解决方案。但首先是一些通用的评论:

  • 您的代码未显示任何内容:请添加
  • 您正在从malloc转换返回值。它在C ++中是必要的,但不在C中:你应该写cmd = malloc(bufsize * sizeof(char));
  • 您可以编写循环for(i=0;i<pipeArrCount;i+=2)删除i=i+2,因为它是C中更常见的用法,或至少for(i=0;i<pipeArrCount;)以避免出现警告。

现在是你问题的真正原因。您为管道分配了一个大小为2*nargc的数组,但只初始化2*(nargc-1)。最后2个没有被初始化,这应该是无害的,但你关闭整个数组for(j=0;j<(2*nargc);j++)。在我的测试中,它们是0(可能是因为调试模式)所以你关闭stdin为您的孩子。只需使用:

for(j=0;j<pipeArrCount;j++)
{
        close(pipefd[j]);
}

这不是全部。你在最后一个命令中有一个拼写错误,你用for(i=0;j<(2*nargc);j++)而不是i写了j。如Kulwant Singh所述,它没有关闭允许代码只运行2个命令的任何内容。

您还必须关闭父进程中的管道。该计划的结束应该是:

    //closing all pipes
    for (j=0; j<pipeArrCount; j++) {
        close(pipefd[j]);
    }
    while ((wpid = wait(&status)) > 0);
}