[comp.unix.programmer] how to use pipes

emmonsl@athena.ecs.csus.edu (L. Scott Emmons) (03/04/91)

I thought that perhaps some people would be interested in just how to use
fork(), exec(), and pipe() to do the same thing as is possible with a
system().  I cooked up a couple of quick programs.  The first implements
redirection using fork(), exec(), and pipe().  The second does the exact
same things, except uses system() instead.

NOTE: I implemented these on a BSD system...It can probably be ported over
      to sysV reasonably easily...change SIGCHLD to SIGCLD, and that should
      be about it...

Just for kicks, I compared the output from 'time' for both versions of the
program.  Here are some average results:

using fork/exec/pipe: 0.0u 0.1s 0:00 35% 5+6k 0+0io 0pf+0w
using system:         0.2u 0.4s 0:00 70% 32+18k 0+4io 0pf+0w

While for this trivial usage the times aren't that much difference, a larger
program surely would be...

Here are the two programs, enjoy and if you have any questions, comments, etc
please feel free to email me at emmons@csus.csus.edu:

---CUT HERE start pipe.c---
/*
	This program shows how to (or one way to) implement fork() and exec()
	on a pipeline, redirecting the stdout of the exec()d program into
	the pipeline.

	This code was written by L. Scott Emmons, emmons@csus.csus.edu.
*/

#include <stdio.h>
#include <signal.h>

child_changed();
int	fd[2];

main()
{
	char	ch=0;

	pipe(fd);

	if (fork()) {
		signal(SIGCHLD,child_changed);
		while(read(fd[0],&ch,1))
			putchar(ch);
		close(fd[0]);
	} else {
		dup2(fd[1],1);
		execl("/usr/ucb/last","last","emmonsl",(char *)0);
	}
}

child_changed()
{
	close(fd[1]);
}
---CUT HERE end pipe.c---

---CUT HERE start system.c---
/*
	This program shows how to (or one way to) use system() to do what
	fork(), exec(), and pipe() can do...  It redirects the output of
	a program to a file, then reads the file back in and prints it.

	This code was written by L. Scott Emmons, emmons@csus.csus.edu.
*/

#include <stdio.h>

main()
{
	FILE *fp;
	char ch;

	system("/usr/ucb/last emmonsl >filename");
	fp=fopen("filename","r");
	while (fread(&ch,1,1,fp))
		putchar(ch);
	fclose(fp);
	unlink("filename");
}
---CUT HERE end system.c---

			L. Scott Emmons
			---------------
	emmons@csus.csus.edu  <or>  ...[ucbvax]!ucdavis!csus!emmons
		Packet: kc6nfp@kg6xx.#nocal.ca.usa.na

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/06/91)

In article <1991Mar3.214844.15444@csusac.csus.edu> emmonsl@athena.ecs.csus.edu (L. Scott Emmons) writes:
> using fork/exec/pipe: 0.0u 0.1s 0:00 35% 5+6k 0+0io 0pf+0w
> using system:         0.2u 0.4s 0:00 70% 32+18k 0+4io 0pf+0w

This is, of course, because you aren't waiting for the child to finish.

---Dan

emmonsl@athena.ecs.csus.edu (L. Scott Emmons) (03/08/91)

In article <5866:Mar604:22:3791@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>This is, of course, because you aren't waiting for the child to finish.


Actually, it does finish...the child closes the pipeline down when it is done.
The read() reads unless eof, which it only returns when the write end of the
pipeline is closed (it blocks if the pipeline is open with no data in it).
I just did it all implicitly...If anyone can come up with an example where
this wouldn't work please let me know. (except the obvious, where the child
doesn't close the pipe, of course...but then, you are changing the
environment of the usage, of course)

Remember also, that I ignored all the return codes for simplicity in the
examples.

Check out my second version, it works the same, but is easier to see how I
implemented this.

			L. Scott Emmons
			---------------
	emmons@csus.csus.edu  <or>  ...[ucbvax]!ucdavis!csus!emmons
		Packet: kc6nfp@kg6xx.#nocal.ca.usa.na

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (03/08/91)

In article <1991Mar7.180531.7907@csusac.csus.edu> emmonsl@athena.ecs.csus.edu (L. Scott Emmons) writes:
> In article <5866:Mar604:22:3791@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> >This is, of course, because you aren't waiting for the child to finish.
> Actually, it does finish...the child closes the pipeline down when it is done.

Irrelevant. Your parent does not call wait(), so your timings are wrong.

---Dan