Question

I need some help emulating the "|" command in unix. I need to be able to use the output from the first argument as the input of the second, something as simple as ls and more. I got this code so far but I'm just stuck at this point. Any and all help would be helpful.-Thanks.

#include <sys/types.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char ** words)
{ 
  char** args;
  char *cmd1[2] = { words[1], 0 };
  char *cmd2[2] = { words[2], 0 };
  int colon, arg1 ,i, pid, status;
  int thepipe[2];
  char ch;
  args = (char **) malloc(argc*(sizeof(char*)));
  colon = -1;
  for (i=0;(i<argc); i=i+1){
    if (strcmp(words[i],":") == 0) {
      colon = i;
    }
    else {}
  }
  pipe(thepipe);
  arg1 = colon;
  arg1 = arg1 - 1;
  for (i=0;(i<arg1); i=i+1){
    args[i] = (char*) (malloc(strlen(words[i+1])+1));
    strcpy(args[i], words[i+1]);
  }
  args[argc] = NULL;
  pid = fork();
  if (pid == 0) {
    wait(&pid);
    dup2(thepipe[1], 1);
    close(thepipe[0]);
    printf("in new\n");
    execvp(*args, cmd1); 
  }
  else {
    close(thepipe[1]);
    printf("in old\n");
    while ((status=read(thepipe[0],&ch,1)) > 0){
    execvp(*args, cmd2);
    }
  }

}
Was it helpful?

Solution

Assuming that argv[1] is a single word command (like ls) and argv[2] is a second single word command (like more), then:

Parent

  1. Create a pipe.
  2. Fork first child.
  3. Fork second child.
  4. Close both ends of the pipe.
  5. Parent waits for both children to die, reports their exit status, and exits itself.

Child 1

  1. Duplicates write end of pipe to standard output.
  2. Close both ends of the pipe.
  3. Uses execvp() to run the command in argv[1].
  4. Exits, probably with an error message written to standard error (if the execvp() returns).

Child 2

  1. Duplicates read end of pipe to standard input.
  2. Close both ends of the pipe.
  3. Uses execvp() to run the command in argv[2].
  4. Exits, probably with an error message written to standard error (if the execvp() returns).

The only remaining trick is that you need to create a vector such as:

char cmd1[2] = { argv[1], 0 };
char cmd2[2] = { argv[2], 0 };

to pass as the second argument to execvp().


Note that this outline does not break the strings up. If you want to handle an invocation such as:

./execute "ls -la" "wc -wl"

then you will need to split each argument into separate words and create bigger arrays for cmd1 and cmd2. If you want to handle more than two commands, you need to think quite carefully about how you're going to manage the extra stages in the pipeline. The first and last commands are different from those in the middle (so 3 processes has three different mechanisms, but 4 or more substantially uses the same mechanism over and over for all except the first and last commands).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top