Read first few lines from command output

Discussion in 'Perl Misc' started by sp0_0ky@yahoo.com, Jul 27, 2005.

  1. Guest

    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
    , Jul 27, 2005
    #1
    1. Advertising

  2. Paul Lalli Guest

    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
    Paul Lalli, Jul 27, 2005
    #2
    1. Advertising

  3. Paul Lalli Guest

    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
    Paul Lalli, Jul 27, 2005
    #3
  4. On 27 Jul 2005 13:47:26 -0700
    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'.
    Sven-Thorsten Fahrbach, Jul 27, 2005
    #4

  5. > 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>;
    Mark Overmeer, Jul 27, 2005
    #5
  6. Mark Overmeer 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'.

    >
    > 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
    John W. Krahn, Jul 27, 2005
    #6
  7. Big and Blue Guest

    >
    > 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.
    Big and Blue, Jul 28, 2005
    #7
  8. Paul Lalli Guest

    Sven-Thorsten Fahrbach wrote:
    > On 27 Jul 2005 13:47:26 -0700
    > wrote:
    >
    > > open(LOTSOFLINES,"mycommand 2>&1|");
    > > count=0;
    > > while (<LOTSOFLINES>)
    > > {
    > > print;
    > > count++;
    > > if ($count > 10)
    > > {
    > > close(LOTSOFLINES);
    > > }
    > > }

    > 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
    Paul Lalli, Jul 28, 2005
    #8
  9. On 27 Jul 2005 19:28:45 -0700
    "Paul Lalli" <> wrote:

    > Sven-Thorsten Fahrbach wrote:
    > > On 27 Jul 2005 13:47:26 -0700
    > > wrote:
    > >
    > > > open(LOTSOFLINES,"mycommand 2>&1|");
    > > > count=0;
    > > > while (<LOTSOFLINES>)
    > > > {
    > > > print;
    > > > count++;
    > > > if ($count > 10)
    > > > {
    > > > close(LOTSOFLINES);
    > > > }
    > > > }

    > > 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
    >


    Yes, that's right, I've mistaken that for the actual problem.
    Sven-Thorsten Fahrbach, Jul 28, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Robert Johnson

    Need a few lines of code help, will pay!

    Robert Johnson, Aug 3, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    313
    makthar
    Aug 4, 2003
  2. Matt Melchert
    Replies:
    7
    Views:
    410
    Chris Smith
    Oct 3, 2003
  3. Joe Wright
    Replies:
    0
    Views:
    496
    Joe Wright
    Jul 27, 2003
  4. Justme
    Replies:
    9
    Views:
    600
    clayne
    Oct 1, 2006
  5. Murali
    Replies:
    2
    Views:
    538
    Jerry Coffin
    Mar 9, 2006
Loading...

Share This Page