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

I'm attempting to make sure that a host is up before I try to get some info from it, so I am using Net::Ping to test for this. The problem is when I try to redirect STDOUT, I get nothing. I can't redirect to a file and writing to a file doesn't work either though the screen output works just fine. Here are some examples of code that works and doesn't work:
# this code works # loop.pl > loop.txt has > 0 bytes use Net::Ping; my $adr = "192.168."; my @net = qw / 97. 100. 102. 104. 105. 32. 33. 34. /; my ($i, $j, $host); for ($i=0; $i<=7; $i++) { HOST: for ($j=16; $j<=250; $j++) { $host = $adr . $net[$i] . $j; print "$host\n"; } }
This, on the other hand, doesn't work:
use Net::Ping; my $adr = "192.168."; my @net = qw / 97. 100. 102. 104. 105. 32. 33. 34. /; my ($i, $j, $host); $p = Net::Ping->new() or die "Can't create ping object: $!\n"; for ($i=0; $i<=7; $i++) { HOST: for ($j=16; $j<=250; $j++) { $host = $adr . $net[$i] . $j; if (!$p->ping($host)) { print "$host not responding!\n"; next HOST; } else { print "$host\n"; } } }
The HOST tag is for a jump that happens in the else clause. The output from the second script is like thus:
192.168.97.16
192.168.97.17
192.168.97.18
192.168.97.19
192.168.97.20
192.168.97.21
192.168.97.22
192.168.97.23
192.168.97.24
192.168.97.25
192.168.97.26 not responding!
192.168.97.27
but when I do ./ploop.pl > ploop.txt, ploop.txt is a 0 byte file and if I open and write to file, still nothing gets written to it. I don't understand what is happening. Anyone have a clue? Thanks in advance

Replies are listed 'Best First'.
Re: Net::Ping and STDOUT
by sk (Curate) on Aug 04, 2005 at 16:16 UTC
    I tried out your code on my system and it works as expected. Something must be wrong with your shell?

    Try these things

    perl -e 'print "hi\n";' > junk

    (or)

    echo hi > junk

    if you see output something strange is happening with your code.

    If the code you showed is part of larger code then you might have to examine that piece as what you gave works just fine!

    Unlikely situation but check your  $| anyways!

    cheers

    SK

Re: Net::Ping and STDOUT
by blazar (Canon) on Aug 04, 2005 at 16:09 UTC
    Since you get the output you desire when printing to STDOUT, you have a problem with shell redirection, hence yours is not a Perl {question,problem} but a {shell,OS} one.

    Or else you may simply have a problem with buffering. Are you trying to read from the file before the writing has terminated? Try adding e.g. $|++ at the top of your script.

    Update: OTOH, it doesn't have anything to do with your problem, but generally Perl-style for loops are preferrable over C-style ones. Your script may be rewritten as (untested):

    #!/usr/bin/perl -l use strict; use warnings; use Net::Ping; my @net=map "192.168.$_", qw/97 100 102 104 105 32 33 34/; my $p=Net::Ping->new or die "Can't create ping object: $!\n"; for my $net (@net) { for (16..250) { my $host="$net.$_"; warn "$host not responding!\n" and next if !$p->ping($host); print $host; } } __END__
    Please note that I also made a few minor, "cosmetic", changes. E.g. I turned a print into a warn. This may not be what you want, but is often appropriate in similar situations.
      I thought that may be the case, but this gives me the same problem on cygwin/bash and OpenBSD/ksh. I'll try your suggestion with the $!++. Thanks.
        Please note that it's $|++, not $!++.
      Your hint about $| was right on the nose, thanks. I'll try to rewrite it with your stylistic input, thanks for that too. I thought that there had to be cleaner way to do the loop, but I'm not familiar with the idioms of perl.
        Well, my coding style isn't the bible. I would say it doesn't differ much from the average one of most perl programmers with some experience, but I'm sure some people would disagree. For example I like very much to use short-circuiting logical operators for flow control. And at times I tend to overuse $_. If it were me chances are that the main loop may have looked like this:
        for my $net (@net) { for (16..250) { local $_="$net.$_"; warn "$_ not responding!\n" and next if !$p->ping($_); print; } }
        And while it's very clear and immediate to me I understand that others' opinion may vary, and expressive variable name like $host may be preferable for maintainability resons.

        Also, if the script were only just a bunch of lines longer, I would have never used the -l switch. Of course I'm eagerly waiting for (Perl6's) say().