[comp.unix.wizards] How do I get EOF from a pipe I created?

richard@aiai.ed.ac.uk (Richard Tobin) (08/07/90)

In article <6366.26be9bd9@csv.viccol.edu.au> timcc@csv.viccol.edu.au (Tim Cook) writes:

>   if (fork ()) {
>      /* Subprocess */

No, fork() returns non-zero in the parent, so you're having the parent
rather than the child exec /dir/command.  This is why you are
returning to the shell and leaving the other process in the
background.  Try

    if(fork() == 0)

instead.

The other problem is that the process reading the pipe doesn't close the
other (write) end.  Read from a pipe returns eof if there is no process
that could write more data.  The parent should do this after the fork():

    close(pipe_descriptors[1]);

-- Richard
-- 
Richard Tobin,                       JANET: R.Tobin@uk.ac.ed             
AI Applications Institute,           ARPA:  R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University.                UUCP:  ...!ukc!ed.ac.uk!R.Tobin

timcc@csv.viccol.edu.au (Tim Cook) (08/07/90)

I am having a bit of fun writing a utility that parses the output of a
command that it exec's in a subprocess.  What I am doing is basically
(minus error checking):

   int pipe_descriptors[2] ;

   pipe (pipe_descriptors) ;
   if (fork ()) {
      /* Subprocess */
      dup2 (pipe_descriptors[1], 1) ;
      execl ("/dir/command", "command", "arg", 0) ;
      /*NOTREACHED*/ }

   /* Parent continues here */
   pipe_stream = fdopen (pipe_descriptors[0], "r") ;

   while (! feof (pipe_stream)) {
      fgets (buffer, sizeof (buffer) - 1, pipe_stream) ;

      /* Parsing of what is in "buffer"... */
      }

Well, I get the output of "command" coming through on "pipe_stream", but
I don't get end-of-file.  The fgets call just blocks when there is nothing
left in the pipe (and not because the last record output by "command" was
not terminated by a newline).

Can anyone help me set this up so that I see EOF?  Can anyone also tell me
how to have the parent process retain control of the tty that it was
invoked on?  At the moment, the shell regains control when the process
exec-ed by the child completes, indicating that the child got control.

md@sco.COM (Michael Davidson) (08/08/90)

In article <6366.26be9bd9@csv.viccol.edu.au> timcc@csv.viccol.edu.au (Tim Cook) writes:
>I am having a bit of fun writing a utility that parses the output of a
>command that it exec's in a subprocess.  What I am doing is basically
>(minus error checking):
>
>   int pipe_descriptors[2] ;
>
>   pipe (pipe_descriptors) ;
>   if (fork ()) {
>      /* Subprocess */
>      dup2 (pipe_descriptors[1], 1) ;

/* Hey!! how about doing a close(pipe_descriptors[0]; here .... */

>      execl ("/dir/command", "command", "arg", 0) ;
>      /*NOTREACHED*/ }
>
>   /* Parent continues here */
>   pipe_stream = fdopen (pipe_descriptors[0], "r") ;

/* Hey!! how about doing a close(pipe_descriptors[1]; here .... */

>
>   while (! feof (pipe_stream)) {
>      fgets (buffer, sizeof (buffer) - 1, pipe_stream) ;

/* now when the child closes the write side of the pipe (probably */
/* when it exits) you should see an EOF ...			  */
/* in the interests of "keeping your process table tidy" it would */
/* also be a really GOOD IDEA (TM) to do a wait() here		*/

>
>      /* Parsing of what is in "buffer"... */
>      }
>
>Well, I get the output of "command" coming through on "pipe_stream", but
>I don't get end-of-file.  The fgets call just blocks when there is nothing
>left in the pipe (and not because the last record output by "command" was
>not terminated by a newline).

Because there is still an open file which refers to the "write"
side of the pipe - the fact that it is in your own process doesn't
matter - you will never get an EOF from a pipe unless you set it
up properly.

In general, unless you *know* how to handle the necessary low level
process and file manipulation necessary to set up pipes correctly
*and* you have a good reason why the functionality provided by
the library routine "popen()" is either unsuitable or inadequate
you should use "popen()" and "pclose()"

timcc@csv.viccol.edu.au (Tim Cook) (08/08/90)

In article <6366.26be9bd9@csv.viccol.edu.au>, I asked for help with pipes.

Well, it seems I did overlook something that should have been obvious. 
Both processes needed to close the write end of the pipe before the read
end would see EOF.  My other problem where my ``child'' process got control
of the tty was due to a switch statement that I wrote but did not
double-check (I did not actually use an if statement like the one in my
example code).  I got the parent confused with the child.

Thanks to those who wrote with answers, and to those who are yet to write
(due to the propagation properties of Usenet and the wizards mailing list).

One last thing.  Only one person has written so far and suggested popen(3),
which would have done what I was wanting to do nicely.  I didn't think of
it because I don't get mention of it when I do a "man -k pipe" on my
system.
--
Tim Cook     Systems Administrator, Victoria College Computer Services

parrot - n.  An animal that has the ability to imitate man, but not the
             intelligence to refrain from doing so.