Nohsib
Nohsib

Reputation: 3722

C program to pipe multiple commands

I have written the below method to fork and execute commands separated by multiple pipes( test with : ls -lrt | grep "check" | wc -l . However it is not resulting in any output, could any one please spot my mistake. Thanks.

   void execCmd (pInfo *info) 
{
  int i, j, k, m;
  struct comType *comm, *comm1, *comm2;
    if(info->noOfPipes > 2)
    {
        // DOES NOT WORK
        printf("Start\n");
        comm=&(info->cArr[0]);
        comm2=&(info->cArr[(info->ppNum)-1]);
        int fds[2];
        pipe(fds);
        pid_t pid = fork();
        if(pid == -1)
        {
            perror("fork failed");
            exit(1);
        }
        if(pid == 0)
        {
            printf("1st child execution here\n");
            close(fds[0]);
            dup2(fds[1], STDOUT_FILENO);
            close(fds[1]);
            execvp(comm->cmd,comm->parms);
        }
        for (k=1;k<=((info->ppNum)-1);k++)
        {
            printf("For loop executionn number %d",k);
            comm1=&(info->cArr[k]);
            printf ("comm 1 : %s\n",comm1->cmd);
            pid = fork();
            if(pid == -1)
            {
                perror("fork failed");
                exit(1);
            }
            if(pid == 0)
            {
                //2nd to n-1 child process
                dup2(fds[0], STDIN_FILENO);
                close(fds[0]);
                dup2(fds[1], STDOUT_FILENO);
                close(fds[1]);
                execvp(comm1->cmd,comm1->parms);
            }
            wait(NULL);
        }
        pid = fork();
        if(pid == -1)
        {
            perror("fork failed");
            exit(1);
        }
        if(pid == 0)
        {
            //nth child process
            printf("Last child execution\n");
            close(fds[1]);
            dup2(fds[0], STDIN_FILENO);
            close(fds[0]);
            execvp(comm2->cmd,comm2->parms);
        }
        close(fds[0]);
        close(fds[1]);
        wait(NULL);
        wait(NULL);
    }
}

Upvotes: 2

Views: 6995

Answers (1)

ThunderWiring
ThunderWiring

Reputation: 738

This following code should give you an idea how to implement the pipelining:

#define STDIN 0
#define STDOUT 1
void exec_cmd(struct comType cmd) {
    execvp(cmd->cmd, cmd->params);
}

void pipeCmds(struct comType* cmds) {
    int fd[cmds_length * 2] = {0};
    pid_t pid = 0;
    for (int i = 0; i < cmds_length; i++) {
        if (pid = fork() == 0) {
            //child: make this cmd's output the other cmd's input
            pipe(fd + (2*i) );
            close(STDOUT);
            dup(fd[i]);
            if(i > 0) {
                close(STDIN);
                dup(fd[i-1]);
            }
            exec_cmd(cmds[i]);
            close(fd[i]);           
        }
    }
}

Note that the main idea is that each command is executed in a separate process (via fork) and the output goes to the next command's input rather than to the default stdout(with file descriptor 1), and the same for the input - stdin (file descriptor 0).

Upvotes: 2

Related Questions