For Programmers: Free Programming Magazines  


Home > Archive > PERL Miscellaneous > July 2005 > Read first few lines from command output









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Read first few lines from command output
sp0_0ky@yahoo.com

2005-07-27, 5:05 pm

Hello,

I have a program which generates many lines of output. I only
need the first few (say 10) lines from the top of the output.
I do not require the program to complete all the output (just
need the first few lines).

The following seems to work, however it complains about "Broken
Pipe" since I am closing the pipe once I get the required data.
I was wondering if there is a cleaner way to do this. The key
is that I do not want to wait for the data command to complete.

open(LOTSOFLINES,"mycommand 2>&1|");
count=0;
while (<LOTSOFLINES> )
{
print;
count++;
if ($count > 10)
{
close(LOTSOFLINES);
}
}

Thanks,
JB

Paul Lalli

2005-07-27, 5:05 pm

sp0_...@yahoo.com wrote:
> I have a program which generates many lines of output. I only
> need the first few (say 10) lines from the top of the output.
> I do not require the program to complete all the output (just
> need the first few lines).
>
> The following seems to work, however it complains about "Broken
> Pipe" since I am closing the pipe once I get the required data.
> I was wondering if there is a cleaner way to do this. The key
> is that I do not want to wait for the data command to complete.
>
> open(LOTSOFLINES,"mycommand 2>&1|");
> count=0;


What language is this? Please post real code.

> while (<LOTSOFLINES> )
> {
> print;
> count++;
> if ($count > 10)
> {
> close(LOTSOFLINES);
> }
> }


Just to be pedantic, that would read the first 11 lines, not 10
(assuming it was actually valid Perl code).

Now, as to your question... From perldoc perlipc:
Prematurely closing the read end of a pipe (i.e.
before the process writing to it at the other end
has closed it) will result in a SIGPIPE being
delivered to the writer. If the other end can't
handle that, be sure to read all the data before
closing the pipe.

In other words, it's not a problem your code can do anything about. If
you have access to the other program, configure it to handle SIGPIPE.
If not, you'll have to either live with the "Broken Pipe" error, or
read all the data.

Paul Lalli

Sven-Thorsten Fahrbach

2005-07-27, 5:05 pm

On 27 Jul 2005 13:47:26 -0700
sp0_0ky@yahoo.com wrote:

> Hello,
>
> I have a program which generates many lines of output. I only
> need the first few (say 10) lines from the top of the output.
> I do not require the program to complete all the output (just
> need the first few lines).
>
> The following seems to work, however it complains about "Broken
> Pipe" since I am closing the pipe once I get the required data.
> I was wondering if there is a cleaner way to do this. The key
> is that I do not want to wait for the data command to complete.
>
> open(LOTSOFLINES,"mycommand 2>&1|");
> count=0;
> while (<LOTSOFLINES> )
> {
> print;
> count++;
> if ($count > 10)
> {
> close(LOTSOFLINES);
> }
> }
>
> Thanks,
> JB
>


Inserting a 'last' does the trick.

while (<LOTSOFLINES> ) {
print;
$count++;
if ($count > 9) {
close (LOTSOFLINES);
last;
}
}

Now perl won't try to get the next line since it never sees the diamond operator in the head of your while loop after the 'last'.
Paul Lalli

2005-07-27, 5:05 pm

Paul Lalli wrote:
> Now, as to your question... From perldoc perlipc:
> Prematurely closing the read end of a pipe (i.e.
> before the process writing to it at the other end
> has closed it) will result in a SIGPIPE being
> delivered to the writer. If the other end can't
> handle that, be sure to read all the data before
> closing the pipe.
>


Whoops. That was from
perldoc -f close
not from perlipc. My mistake.

Paul Lalli

Mark Overmeer

2005-07-27, 5:05 pm


> Inserting a 'last' does the trick.
>
> while (<LOTSOFLINES> ) {
> print;
> $count++;
> if ($count > 9) {
> close (LOTSOFLINES);
> last;
> }
> }
>
> Now perl won't try to get the next line since it never sees the diamond operator in the head of your while loop after the 'last'.


The file isn't closed if it is too short...

while( <LL> )
{ print;
last if ++$count > 9;
}
close LL;

Or

while( <LL> )
{ print;
last if $.==9;
}

Or

print while <LL> && $. < 10;

Or ...

But it will probably not solve your "broken pipe". A typical warning in
old UNIX programs. You could do
1 while <LL>;
close <LL>;

John W. Krahn

2005-07-27, 5:05 pm

Mark Overmeer wrote:
>
>
> The file isn't closed if it is too short...
>
> while( <LL> )
> { print;
> last if ++$count > 9;
> }
> close LL;
>
> Or
>
> while( <LL> )
> { print;
> last if $.==9;
> }
>
> Or
>
> print while <LL> && $. < 10;


That won't print anything because <LL> only assigns to $_ when it is the
only expression in the while condition.

print while defined( $_ = <LL> ) && $. < 10;



John
--
use Perl;
program
fulfillment
Big and Blue

2005-07-27, 10:01 pm

>
> I was wondering if there is a cleaner way to do this. The key
> is that I do not want to wait for the data command to complete.


As has been pointed out, it's the process generating the data which is
sent the SIGPIPE and hence would need to handle it.

Since you don't want to wait in your script then, if you can't get the
other side to handle SIGPIPE:

1) read as much as you need to
2) fork()
3) let the child continue to read (and discard) the rest of the input while
4) the parent continues to do what you want it to.

You may wish to get the child to fork twice (so the parent quickly sees
its child die() and so won't wait for it), to close the read handle in the
parent and to detach the child even more (eg: setsid from POSIX), but that
is left up to you....


--
Just because I've written it doesn't mean that
either you or I have to believe it.
Paul Lalli

2005-07-27, 10:01 pm

Sven-Thorsten Fahrbach wrote:
> On 27 Jul 2005 13:47:26 -0700
> sp0_0ky@yahoo.com wrote:
>
> Inserting a 'last' does the trick.
>
> while (<LOTSOFLINES> ) {
> print;
> $count++;
> if ($count > 9) {
> close (LOTSOFLINES);
> last;
> }
> }
>
> Now perl won't try to get the next line since it never sees the diamond
> operator in the head of your while loop after the 'last'.


It is not the <> operation that causes the broken pipe error, it is the
close() statement. However, assuming the close *does* work, your last
statement will prevent the "read on closed filehandle" warning for the
remainder of the loop.

Paul Lalli

Sven-Thorsten Fahrbach

2005-07-28, 9:09 am

On 27 Jul 2005 19:28:45 -0700
"Paul Lalli" <mritty@gmail.com> wrote:

> Sven-Thorsten Fahrbach wrote:
>
> It is not the <> operation that causes the broken pipe error, it is the
> close() statement. However, assuming the close *does* work, your last
> statement will prevent the "read on closed filehandle" warning for the
> remainder of the loop.
>
> Paul Lalli
>


Yes, that's right, I've mistaken that for the actual problem.
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com