[comp.unix.questions] Why does pipeline work this way?

ray@saturn.ucsc.edu (Ray Swartz) (12/15/89)

I have discovered an anomoly that I can't explain and want to know
what is going on.

If you have a large data file (mine is > 3 Megs) and you want to 
use grep to find a line in the file, you have to wait for the grep to 
read through the entire file.  To get around this problem, I decided to
write a shell script that would get piped the output from the grep
and upon reading the first line from the pipe (there will only be one
line of output) terminate the grep process.  Here's the problem, the
shell script (using 'while read data' to read the pipe) doesn't get
the output from grep right away.  In fact, grep still reads
through the entire file before the shell script gets the output.

While studying this further, I tried to see if cat had the same problem.
The command

	grep "pattern" bigfile | cat

also doesn't show output until the grep command completes.

I even tried doing the forking and execing myself and it still waited
until the grep finished.

Yet, when I run grep by itself, the output comes out to the tty as soon as grep
finds a line.  Why is it that when grep prints to a terminal the output
appears unbuffered and when it is going into a pipe, it appears buffered?

Any and all comments appreciated.

cpcahil@virtech.uucp (Conor P. Cahill) (12/16/89)

In article <10064@saturn.ucsc.edu>, ray@saturn.ucsc.edu (Ray Swartz) writes:
> Yet, when I run grep by itself, the output comes out to the tty as soon
>  as grep finds a line.  Why is it that when grep prints to a terminal
> the output appears unbuffered and when it is going into a pipe, it
> appears buffered?

Grep writes it's matches to stdout which is buffered by line on output
to a terminal and buffered by data block on any other output medium, including
pipes.

If you really want this functionality, get the gnu grep sources and add
a parameter to stop looking after the first match (i.e. only show the
first matching record).  Or you could make it reall inefficient and turn
off all buffering, but I don't recommend this.


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

maart@cs.vu.nl (Maarten Litmaath) (12/19/89)

In article <1989Dec16.133416.3855@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes:
\... If you really want this functionality, get the gnu grep sources and add
\a parameter to stop looking after the first match [...]

Or use sed:

	$ SED="
		/$pattern/!d
		p
		q
	"
	$ sed "$SED" file
-- 
  Sci.aquaria votes are only poisson distributed in France.  (Alan M Stanier) |
 Maarten Litmaath @ VU Amsterdam:  maart@cs.vu.nl,  uunet!mcsun!botter!maart

morrell@hpsal2.HP.COM (Michael Morrell) (12/19/89)

/ hpsal2:comp.unix.questions / cpcahil@virtech.uucp (Conor P. Cahill) /  5:34 am  Dec 16, 1989 /
If you really want this functionality, get the gnu grep sources and add
a parameter to stop looking after the first match (i.e. only show the
first matching record).
----------

You could also use sed (as in "sed '<pattern>p;q'") which will stop reading
the input after the match.

  Michael

jba@harald.ruc.dk (Jan B. Andersen) (12/21/89)

ray@saturn.ucsc.edu (Ray Swartz) writes:

>Any and all comments appreciated.

Use sed:

  % sed -n '/pattern/p;//q' file

It don't answer your question about pipes but it solves the original
problem.