ngwilliams
ngwilliams

Reputation: 269

How to create a linux pipeline example in c

I am trying to learn how to use the pipe() command in C, and trying to create a test program to duplicate the functionality of ls | grep ".c", if I were to enter this into a linux terminal. If I enter this into the terminal, I only get test.c as a result.

My code is as follows:

#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "fcntl.h"

int main(int argc, char** argv)
{
 int pipefd[2];
 int childpid,childpid2;
 char* cmd[3]={"ls",NULL,NULL};
 char* cmd2[3]={"grep",".c",NULL};
 pipe(pipefd);
 if(childpid=fork()){
   //parent
 }else{  
   //child
   //write
   close(pipefd[0]);
   dup2(pipefd[1],STDOUT_FILENO);
   execvp("ls", cmd);
 }
 if(childpid2=fork()){
 }
 else{
   close(pipefd[1]);
   dup2(pipefd[0],STDIN_FILENO);
   execvp("grep",cmd2);
 }
 close(pipefd[0]);
 close(pipefd[1]);
 return 0;
}

This code returns me the following results ($ is the terminal prompt):

$a.out
$test.c
(blank line)

The program doesn't complete, but hangs until I quit it. What problems do I have? How can I mimic the terminal? I'm new to C, and using a premade template of a program, so forgive me if there are glaring mistakes.

Upvotes: 6

Views: 14109

Answers (4)

jww
jww

Reputation: 102346

This question is a bit old, but here's an older answer that was never provided. Use libpipeline. libpipeline is a pipeline manipulation library. The use case is one of the man page maintainers who had to frequently use a command like the following (and work around associated OS bugs):

zsoelim < input-file | tbl | nroff -mandoc -Tutf8

Here's the libpipeline way:

pipeline *p;
int status;

p = pipeline_new ();
pipeline_want_infile (p, "input-file");
pipeline_command_args (p, "zsoelim", NULL);
pipeline_command_args (p, "tbl", NULL);
pipeline_command_args (p, "nroff", "-mandoc", "-Tutf8", NULL);
status = pipeline_run (p);

The libpipeline has more examples on its homepage. The library is also included in many distros, including Arch, Debian, Fedora, Linux from Scratch and Ubuntu.

Upvotes: 0

that other guy
that other guy

Reputation: 123570

Your program quits immediately, while your processes run in the background. They overwrite the prompt, and makes you think the program is still running even though the shell is waiting for your input (press enter or type a command blindly and see.

You only see test.c because that's the only matching file in your directory (also note that you're checking for "filenames containing c anywhere except the first character", not "ending in .c" which would be grep '\.c$').

The simple fix is to add:

wait(NULL); wait(NULL);

right before your return 0.

Upvotes: 1

hobbs
hobbs

Reputation: 240314

Actually the program exits right away — in fact, the parent process exits before the children run, which is why there's a shell prompt before "test.c".

You can improve things a bit by adding this in your parent:

wait(childpid);
wait(childpid2);

which will make the parent exit after both children.

Upvotes: 3

Lee Duhem
Lee Duhem

Reputation: 15121

Try this:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char** argv)
{
 int pipefd[2];
 int childpid,childpid2;
 char* cmd[3]={"ls",NULL,NULL};
 char* cmd2[3]={"grep",".c",NULL};
 pipe(pipefd);
 if(childpid=fork()){
   //parent
   close(pipefd[1]);
   dup2(pipefd[0],STDIN_FILENO);
   execvp("grep",cmd2);
 }else{  
   //child
   //write
   close(pipefd[0]);
   dup2(pipefd[1],STDOUT_FILENO);
   execvp("ls", cmd);
 }
 return 0;
}

Upvotes: 5

Related Questions