Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Non-buffered read from program

by arc_of_descent (Hermit)
on Dec 30, 2005 at 12:56 UTC ( [id://519982]=perlquestion: print w/replies, xml ) Need Help??

arc_of_descent has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

I'm stuck with this problem. I searched the docs and this site, but most of them deal with non-buffered output.

What I'm looking for is a way to read the output from a command which initially shows some output, and then blocks due to a network issue

This is the command when run on a Linux shell:

$ whois x.x.x.x [Querying whois.server.net]

The above command then hangs, most probably as that particular server is not available. Whats important is that this command does indicate which server it is trying.

I'm running the above command in a Perl script, and trying to capture the initial 2-3 lines, irrespective of whether the command blocks or not.

None of the following work:

open FH, "whois x.x.x.x 2>&1 |"; my $ofh = select FH; $|=1; while (<FH>) { print; } close FH;
open FH, "whois x.x.x.x 2>&1 |"; sysread FH, $output, 4192; close FH;

Any help would be much appreciated. Thanks!


--
Rohan

Replies are listed 'Best First'.
Re: Non-buffered read from program
by derby (Abbot) on Dec 30, 2005 at 13:41 UTC

    open FH, "whois x.x.x.x 2>&1 |"; my $ofh = select FH; $|=1; while (<FH>) { print; } close FH;

    Turn on warnings and you'll see exactly what the problem is with this piece of code.

    -derby
Re: Non-buffered read from program
by rinceWind (Monsignor) on Dec 30, 2005 at 13:35 UTC

    Check out IO::Select, which does what you want.

    --

    Oh Lord, won’t you burn me a Knoppix CD ?
    My friends all rate Windows, I must disagree.
    Your powers of persuasion will set them all free,
    So oh Lord, won’t you burn me a Knoppix CD ?
    (Missquoting Janis Joplin)

      IO::Select seems like a good choice, but unfortunately it does not work. i.e. if the whois server is unavailable, I get no output.

      open my $WHOIS, "jwhois x.x.x.x 2>&1 |"; my $s = IO::Select->new($WHOIS); while (my @ready = $s->can_read) { for my $fh (@ready) { if ($fh == $WHOIS) { my $buf = <$fh>; if ($buf) { print $buf; } else { close($fh); } } } }

      Note that this works great, if the server sends some output and then closes the connection, but not for servers which send some output and then hang.


      --
      Rohan

Re: Non-buffered read from program
by PreferredUserName (Pilgrim) on Dec 30, 2005 at 19:22 UTC
    Fundamentally, the problem is that when the "whois" program (or most any other program) prints to its standard output using the standard C libraries, it does so in a heavily buffered fashion *unless* it's printing to a terminal, in which case its output is buffered line-by-line.

    Since his standard output is connected to your standard input, and not to a terminal, it is heavily buffered.

    Mucking around with $| will never help, since it's the other program's buffering, not your own, that's causing the problem.

    The solution is to trick it into thinking it's talking to a terminal by using Expect.pm or Expect::Simple.

      Yes. Expect did solve this problem for me. Especially the raw_pty method.


      --
      Rohan

        Or if you don't want to use Expect when you're not planning on using all of its complexity, you could do something like: http://www.perlmonks.org/?node_id=393312 to put a pesudo-tty inbetween you and the command.
Re: Non-buffered read from program
by myuji (Acolyte) on Dec 30, 2005 at 13:44 UTC
    Try this code:
    open FH, "whois x.x.x.x 2>&1 |"; my $ofh =select(FH); $|=1; select($ofh); #changed while (<FH>) { print; } close FH;
    On my environment ,this works good. Hope this helps,

      Doesn't seem to work on mine. IO::Handle too does not help.

      use strict; use warnings; use IO::Handle; open my $WHOIS, "jwhois x.x.x.x 2>&1 |"; my $io = IO::Handle->new; $io->fdopen($WHOIS, "r"); $io->blocking(0); print $io->getline; $io->close;

      I don't get any output, if the server is unavailable.


      --
      Rohan

        Do you mean to use $io->autoflush(1) ? Try this code:
        use strict; use warnings; use IO::Handle; open my $WHOIS, "whois x.x.x.x 2>&1 |"; my $io = IO::Handle->new; $io->fdopen($WHOIS, "r"); $io->autoflush(1); while(my $line = $io->getline){ print $line; } $io->close;
        This is working fine on my environment.
Re: Non-buffered read from program
by Celada (Monk) on Dec 30, 2005 at 16:41 UTC

    Both sysread and <FH> will return immediately if some data (for <FH>, a whole line) were collected from the pipe. There is no need to turn on autoflush ($|) for the FH filehandle. If you are not getting the data it is because whois is probably not sending it. Probably it is using stdio, and since its output is a pipe, it is buffered. If that's the case, then there's not much you can do about it. None of the versions of whois that I have produce this status message so I cannot test whether this is so, but you can verify whether yours is outputting any data with truss or strace:

    truss -t write whois x.x.x.x 2>&1 | cat
Re: Non-buffered read from program
by holli (Abbot) on Dec 30, 2005 at 13:18 UTC
    I have no idea about the whois command, but there are a couple of modules that seem to be relevant, most likely Net::Whois.


    holli, /regexed monk/

      Its not particularly about the whois command, but on how to obtain program output which blocks. The whois command is a perfect example for this.


      --
      Rohan

        perhaps the backticks will give you a way. Then you can use something like this $myvar = `whois x.x.x.x` ; Then you can manipulate/search/test the output from the command, through $myvar. G
Re: Non-buffered read from program
by zentara (Archbishop) on Dec 30, 2005 at 16:39 UTC
    If you read "perldoc -f select", it allows you to put a timeout on the select statement, maybe that is what you are after?

    Or maybe you want to regex the output, and if it is empty, leave the loop.


    I'm not really a human, but I play one on earth. flash japh

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://519982]
Approved by ww
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2024-04-19 22:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found