2

suppose there are multiple commands passed by a user on shell say

command 1 | command 2 | command 3 | command 4

so I have written a sample program which reads command 1|command 2 inside char str[] (right now for simplicity I have hard coded the commands inside program)

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main()
{
  char str[] = "ls -al| grep test.txt"; 


  char *commands[10]; // Array to hold a max of 10 commands
  char *semi = "|";
  char *token = strtok(str, semi);
  int i = 0;
  while (token != NULL)
  {
    commands[i] = token;
    ++i;
    token = strtok(NULL, semi);
  }
  int numCommands = i; // numCommands is the max number of input commands


  i = 0;
  while (i < numCommands)
  {
    printf("Command: %s\n", commands[i]);


    char *args[10] = {}; // Array to hold command args
    args[0] = strtok(commands[i], " ");
    int tokenCounter = 0;
    while (args[tokenCounter] != NULL)
    {
      tokenCounter++;
      args[tokenCounter] = strtok(NULL, " ");
    }


    int childpid = fork();


    if (childpid == 0)
    {
      if ((execvp(args[0], args)) < 0)
      {
        printf("Error! Command not recognized.\n");
      }
    exit(0);
    }

    else if (childpid > 0)
    {
      wait(&childpid);
    }
    else
    {
      printf("Error: Could not create a child process.\n");
      exit(1);
    }

    ++i;
  }

  return 0;
}

I understand that I need to use dup2 and pipe in this situation I went through many tutorials also, but in the code above when I am executing commands inside while loop i.e. while (i < numCommands) then the commands are being executed independently while what I want to achieve here since the number of commands which user can pass on shell could be n so how can I implement n pipes which I can use in while loop for execution to read write.More specifically I want to concatenate out put of one command to other command in pipe. Multiple piped programs in a command line are separated with the token "|". A command line will therefore have the following form:

 <program1><arglist1> | <program2><arglist2> | ... | <programN><arglistN> [&]

Multiple processes I have launched in above program but how do I connect them using pipe in a normal situation when I would have been aware of how many pipes I am supposed to use I would have constructed them and passed the inputs. But here number is not specified as how many commands a user can pass.So how can I go for implementing multiple pipes in this situation. Any logic which can lead to solution of my problem is what I am looking for.

ss321c
  • 689
  • 2
  • 11
  • 23
  • You say you would know how to do it if you knew how many commands there would be, but you *do* know, before entering the `while` loop, how many there actually are. You can count them while or after you tokenize. At worst, that means you have to do some dynamic allocation instead of relying on automatic. – John Bollinger Aug 27 '18 at 14:52
  • yes correct I am not getting the dynamic allocation part for pipes – ss321c Aug 27 '18 at 15:05

1 Answers1

0

You'll need a pipe pair for each program that pipes into another. So if you have n programs, you'll need n-1 pairs of pipes.

Also, you'll need to start the programs in the reverse order in which they are specified. That way, the program at the read end of the pipe is ready to start reading when the program that does the writing starts up.

For simplicity's sake, we'll show this for one pair of commands:

char *cmd1[] = { "ls", "-l", NULL }; 
char *cmd2[] = { "grep", "test.txt", NULL };
int p[2];

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

pid_t p2 = fork();
if (p2 == -1) {
    perror("fork failed");
    exit(1);
} else if (!p2) {
    close(p[1]);
    dup2(p[0], 0);
    execv(cmd1[0], cmd1);
    perror("exec failed");
    exit(1);
}

pid_t p1 = fork();
if (p1 == -1) {
    perror("fork failed");
    exit(1);
} else if (!p1) {
    close(p[0]);
    dup2(p[1], 1);
    execv(cmd2[0], cmd2);
    perror("exec failed");
    exit(1);
}

You can extend this to work with more than two processes.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    The OP claims that his main confusion is about exactly the parts that this answer glosses over: how to implement this for more than two commands, where, moreover, the exact number is not known until runtime. – John Bollinger Aug 27 '18 at 14:55