将标准输出放入管道

Put stdout in a pipe

我想知道一个词在不同文件中重复的次数, 为此,我需要使用 fork() 函数并为每个文件创建一个子文件,它将找到这个数字并将不同的结果添加到父文件中。

我成功找到了出现次数,但无法将此信息传达给家长。

我知道我需要使用 pipe 和 dup2。我以前都用过,但分开用过,我不能说我对它们很满意。

正如您在变量 'temp' 中看到的那样,管道是空的。一开始我以为是同步问题,但好像不是这样。我的理解是 dup2(tube[1],1) 将 stdout 放入管道,但我开始怀疑了。

我错过了什么?

int main(int argc, char const *argv[])
{
    int tube[2];pipe(tube);int temp;
    int s=0;

    for (int i = 2; i < argc; i++)
    {
        if (fork()==0)
        {
            dup2(tube[1],1);
            close(tube[1]);
            close(tube[0]);
            execlp("grep","grep","-c",argv[1],argv[i],NULL);
        }
    }

    wait(NULL);

    for (int i = 2; i < argc; i++) {
        {
            close(tube[1]);
            close(tube[0]);
            read(tube[0],&temp,sizeof(int));
            printf("temp=%d\n",temp);
            s+=temp;
        }
    }

    printf("s=%d",s);
    return 0;
}

pipie()后,返回的第一个文件描述符(FD)是管道的reader端,第二个FD是writer端。所以,你需要关闭子路径中的第一个FD,以及你程序的父路径中的第二个DF。

不得关闭父路径中的第一个 FD,因为您希望父路径读取客户端的内容写了。而且你一定不要关闭子路径中的第二个FD;否则它如何能够写入管道。

请记住,stdout 被认为是为用户输出的,即 text。因此,您的代码需要接收一个 字符串 (匹配行的计数),然后测试一个有效数字,并将其转换为 int (long int, long long int), 可以总结一下。

此外,在父进程从管道读取之前,可能有多个子进程写入了它的结果,即在一次读取中可能会读取多个以换行符结尾的字符串。

最后,你需要wait()每个子进程,否则它们会变成僵尸。

这个问题让我很好奇,所以我试着想出了一些工作代码。

//------------------------------------------------------------------------------
//
// The purpose of this program is to find the total number of lines containing
// the specified grep pattern in all the files specified. 
//
// Parameters:
//  pattern file [ file [ ... ] ]
//
//  pattern  ->  search pattern to be passed to grep
//  file     ->  file(s) to be scanned for "pattern" occurences.
//
//------------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main( int argc, char* argv[] ) {

    int pipefd[2];
    int totalCount = 0;

    //----------------------------------------
    // Open a pipe to receive the result from
    // running "grep" in the child processes.
    //----------------------------------------
    pipe(pipefd);

    //---------------------------------------------------------
    // Start a child process for each file given as parameter. 
    // First file is passed as argument #2.
    //---------------------------------------------------------
    for ( int ii = 2; ii < argc; ii++ ) {

        //------------------------
        // This is the child code
        //------------------------
        if ( fork() == 0 ) {

            //-----------------------------
            // Redirect stdout to the pipe
            //-----------------------------
            dup2( pipefd[1], 1 ); 

            //------------------------------------
            // Close the reader side of the pipe.
            //------------------------------------
            close( pipefd[0] );

            execlp( "grep", "grep", "-c", argv[1], argv[ii], NULL ); 
        }
    }

    //-----------------------------------------------------------------------
    // This is the parent code. 
    // 
    // There possibly is more than one child process writing to the pipe. 
    // Writes and reads are atomic, however, more than one child may be able
    // to write to the pipe before the parent can read.
    //-----------------------------------------------------------------------
    for ( int ii = 2; ii < argc; ii++ ) {

        char result[1024];
        int bytesRead;
        int ss, pp;

        //---------------------------
        // Close writer side of pipe
        //---------------------------
        close( pipefd[1] );

        //----------------------------------------------------------
        // Read the data that one or more child process has written
        //----------------------------------------------------------
        bytesRead = read( pipefd[0], &result, sizeof( result ) );
        
        if ( bytesRead > 0 ) {
            //---------------------------------------------------------
            // One or more *newline terminated* string has been read
            // from the pipe, representing the result from one or
            // more grep command that has finised.
            //
            // Each newline terminated string is converted to a zero
            // terminated C-sytle string, so that it can be passed to
            // atoi(). 
            //---------------------------------------------------------
            ss = 0;

            for ( pp = 0; pp < bytesRead; pp++ ) {
                if ( result[pp] == '\n' ) {
                    result[pp] = 0x0;
                    totalCount += atoi( &result[ss] );
                    ss = pp + 1;
                }
            }
        }

        wait( NULL );
    }

    //-----------------------------------
    // Print the final result and return
    //-----------------------------------
    printf("Total number of matches: %d\n\n", totalCount );
    return 0;
}

4 月 19 日的编辑:从中间代码版本中删除了一些剩余的内容。阐明了从换行符终止到零终止字符串的转换。