Sunday, October 03, 2010

Writing your own shell… stuck on pipes?

I spent several hours nail down how to do pipe if you are writing your own shell. Most of the online reference is focusing 2 commands only. Here is the example of having 3 commands pipe together: ls -al | sort | cat -n

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

static const int PIPE_READ = 0;
static const int PIPE_WRITE = 1;

int main(int argc, char **argv)
{
int status;
int fd[2];
pid_t pid;

pid = fork();
if (pid == 0) {

pipe(fd);
if (fork() == 0) {
dup2(fd[PIPE_WRITE], STDOUT_FILENO);
close(fd[PIPE_READ]);
close(fd[PIPE_WRITE]);

pipe(fd);
if (fork() == 0) {
dup2(fd[PIPE_WRITE], STDOUT_FILENO);
close(fd[PIPE_READ]);
close(fd[PIPE_WRITE]);
execlp("ls", "ls", "-la", NULL);
} else {
dup2(fd[PIPE_READ], STDIN_FILENO);
close(fd[PIPE_WRITE]);
close(fd[PIPE_READ]);
}

execlp("sort", "sort", NULL);
} else {
dup2(fd[PIPE_READ], STDIN_FILENO);
close(fd[PIPE_WRITE]);
close(fd[PIPE_READ]);
}

/* IMPORTANT: don't add any wait/waitpid here */
//waitpid(pid2, &status, 0);

execlp("cat", "cat", "-n", NULL);
}
waitpid(pid, &status, 0);
return EXIT_SUCCESS;
}


You can easily refactor this to a recursive function. Pay attention to not have the waitpid/wait() at the first and second command, or your child processes will block at wait.

2 comments:

Ambika said...

Hi Mathew,

I am able to exectly get the code you have written.
I am able to do the same for 4 pipes.
But could you tell me a way i can do this for any number of pipes..As you have mentioned(using recursion)

I am assuming the commands are present in a COMMAND_ARRAY

Unknown said...

Thank you, this was very helpful! :)