将标准输出放入管道

问题描述

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

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

我知道我需要使用管道和 dup2。我之前都使用过它们,但分开使用,我不能说我对它们感到满意。

正如您在变量 'temp' 中看到的那样,管道是空的。起初我以为是同步问题,但似乎并非如此。我的理解是 dup2(tube[1],1) 将标准输出放入管道中,但我开始怀疑。

我想念什么?

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 是写入端。因此,您需要关闭子路径中的第一个 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 日起编辑:从中间代码版本中删除了一些剩余内容。阐明了从换行符终止到零终止字符串的转换。