mkab
mkab

Reputation: 953

Implemeting pipes in Linux Shell with C

I'm trying to implement a simple shell program that supports multiple piping. For now my shell can implement some simple builtin commands and also external commands. I did this by getting the user input from the command line which is separated by space " " and put each string in a char* argv[]. The problem now is executing pipes. I read a litle bit about it in this link http://www.cs.loyola.edu/~jglenn/702/S2005/Examples/dup2.html. And I understood how it works.

So I thought about strcmp each argv[i] with "|" and when I meet a pipe, I fork a new process. I then put the strings before the pipe in a char* argv[] and the one after the pipe in another char* argv[]. This might work for 1 pipe but if the user entered multiple have multiple pipes, things might get tedious with this method. My main problem is about separating the strings at both ends of the pipes. Any ideas on how I can implement it? Thanks.

Upvotes: 1

Views: 1471

Answers (2)

thiton
thiton

Reputation: 36049

Divide and conquer:

  1. Find the first pipe argument
  2. If no pipe is found, execute the array with stdout as output and terminate.
  3. Divide the argument array between the non-pipe first part and the rest.
  4. Make a pipe and execute the non-pipe first part with the pipe as output
  5. Remove the non-pipe first part and the pipes from the argument array
  6. Goto 1

Step 3 is, due to C array semantics, pretty simple:

char **arguments;
int pipe_position = /* for example: */ 5;
assert( strcmp( arguments[pipe_position], "|" ) == 0 );
arguments[pipe_position] = NULL;
char **my_arguments = arguments;
arguments = arguments + pipe_position + 1;

and then my_arguments is an array of length pipe_position containing the first arguments, and arguments is an array of length argc - pipe_position - 1 containing the rest. You can give these pointers to execvp without a problem. Yes, they point to the same block of memory, but that's not execvp's concern.

Upvotes: 2

Has QUIT--Anony-Mousse
Has QUIT--Anony-Mousse

Reputation: 77454

You can probably even just reuse the argv array by replacing the pipes with a null string (which terminates the argv array).

So your array was something like this:

"a", "b", "|",  "c", "d", "e", "|",  "f", "g", "h", NULL

which you change into

"a", "b", NULL, "c", "d", "e", NULL, "f", "g", "h", NULL

and voila, here are your three command lines: argv, argv+3, argv+7

The difficult part with pipes is setting up the stdin and stdout file descriptors, not the actual execution of commands.

Upvotes: 2

Related Questions