Search code examples
cgrepfork

Grep concatenation in C


I am trying to do a multiple grep using c language. Here is the code

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char** argv)
{
    int pid1, pid2;
    int stdout = 1;
    int pipefd[2];

    char* name = malloc(sizeof(char) * 100);
    char* year = malloc(sizeof(char) * 100);

    bzero(name, sizeof(name));
    bzero(year, sizeof(year));

    pid1 = fork();

    if(pid1 == 0){
        strcpy(name, "Jack");
        strcpy(year, "2018");
        close(1);

        if(pipe(pipefd) == -1){
            perror("pipe");
            exit(-1);
        }

        pid2 = fork();
        dup(pipefd[1]);
        close(pipefd[1]);
        execlp("grep", "grep", year, "file.txt", (char*)NULL);

        if(pid2 == 0){
            read(pipefd[0], &stdout, sizeof(stdout));
            int a = dup2(pipefd[0], 0);
            close(pipefd[0]);
            execlp("grep", "grep", name, a, (char*)NULL);
        }
    } else if (pid1 < 0){
        printf("pid error\n");
    }
}

So basically it gives me error in the first exec, saying that the file descriptor is invalid. I didn't find a solution to pass the result of the first exec to the second fork.


Solution

  • Your program behaves like this (I only look at fork and exec calls):

    • creation: process A
    • fork: you have 2 processes: A(parent) and B(child)
    • you do nothing more in A
    • in B, you make a fork: you have 2 processes B and C its child
    • in both B and C you exec a grep command.
    • your code is no longer executed in B and C : they have been replaced by grep processes.

    But, you were not far to a solution.

    What you have to do is:

    • create a pipe in the parent process
    • create the first child
      • setup its i/o
      • exec the child program
    • create the second child

      • setup its i/o
      • exec the child program
    • wait for child to end.


    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main(int argc, char **argv)
    {
        int pid1, pid2;
        int stdout = 1;
        int pipefd[2];
    
        /* patterns to search */
        char name[] = "Jack";
        char year[] = "2018";
    
        /* pipe creation */
        if (pipe(pipefd) == -1) {
            perror("pipe");
            exit(-1);
        }
    
        /* create first child */
        pid1 = fork();
        if (pid1 == 0) {
            close(pipefd[0]);
            dup2(pipefd[1], 1);
            close(pipefd[1]);
            execlp("grep", "grep", year, "file.txt", (char *) NULL);
        }
    
        /* second child */
        pid2 = fork();
        if (pid2 == 0) {
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            close(pipefd[0]);
            execlp("grep", "grep", name, "-", (char *) NULL);
        }
    
        /* close pipe to prevent child hang up */
        close(pipefd[0]);
        close(pipefd[1]);
    
        while (1) {
            pid_t cid = wait(NULL);
            if (-1 == cid)
                break;
            printf("process %d terminated\n", cid);
        }
    
    }