Beefy Boxes and Bandwidth Generously Provided by pair Networks RobOMonk
go ahead... be a heretic
 
PerlMonks  

Trouble with Array or ??

by Anonymous Monk
on Nov 07, 2011 at 03:40 UTC ( #936394=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I am new to Perl and have spent about 15 hours (mostly on google, tutorials and bought a Perl book) trying to figure out what I assumed was a simple thing to do.

I have 3 files: host.file - which has IP addresses and possibly hostnames email.file - which is an output file that is updated when I am emailed about a failed ping. output.file - basically just used for debugging/logging

What I am trying to do is ping a list of hosts/IPs then email myself if the ping fails. So far I can get all of that to work. I run the script like every 5 minutes. The 'problem' is that I do not want it to email me every 5 minutes when it detects a failure, I would like it to add that IP to a list (email.file) then notice that I just emailed it and skip over it a few times, maybe for 60 minutes or something before it clears from the list and is available to be emailed again when the ping fails. I hope that makes sense.

In the code I commented out my failed attempts, and removed most of the Net::SMTP stuff just to clean up the code. The trouble area I assume is around the while (@efile = <eFILE>) { area.

Sorry about the sloppy code, I am new to coding, thanks, Sam.

#!/usr/local/bin/perl -w use Net::Ping; #use Net::SMTP; sub email() { print "emailed: $_\n"; print eFILE ("$_\n"); } open(INFILE, "<", "host.file") or die("unable to open file: $!"); my @ip_array = <INFILE>; chomp(@ip_array); open(OUTFILE, ">", "output.file") or die("unable to write to file: $!" +); open(eFILE, "+<", "email.file") or die("unable to write to file: $!"); my @efile = <eFILE>; chomp(@efile); $p = Net::Ping->new(); foreach (@ip_array) { if($p->ping($_)) { print OUTFILE ("$_ is responding to ping.\n"); }else{ print OUTFILE ("$_ is NOT responding to ping.\n"); #while (@efile = <eFILE>) { #if (@efile =~ $_) { #print "found $_ on the list.\n" #}else{ email() #} #} } } close(INFILE); close(OUTFILE); close(eFILE);

Comment on Trouble with Array or ??
Download Code
Re: Trouble with Array or ??
by patcat88 (Chaplain) on Nov 07, 2011 at 03:54 UTC
Re: Trouble with Array or ??
by GrandFather (Cardinal) on Nov 07, 2011 at 04:35 UTC

    First a few things that are nothing to do with your immediate problem, but do relate to your "sloppy code" comment:

    First, always use strictures (use strict; use warnings;) Warnings (the -w switch on the "command line") are good, but strict is much better because to performs what amounts to a static analysis of your code to alert you to common errors like mismatched variable names.

    Don't use subroutine prototypes (sub proto () { the () makes it a prototype). They don't do what you think and will bite you on the bum!

    Don't overuse the default variable ($_). It gets clobbered all over the place so is a great source of bugs and using it doesn't help understand the code - a named lexical variable (one declared with my) is much better on both counts.

    It's great to see you using three parameter open and checking the result. It would be even better if you used a lixical file handle (one declared with my) and in your error message said which file failed to open.

    Ok, now to address your real problem. First off what you have commented out would only be a one shot test because by the end of the loop the file handle is stuck at the end of the file. You'd have to reset the file handle, or re-open the file to fix that. However rereading a file multiple times is bad design. Much better to read the data once into a data structure you can look up in memory. Consider:

    #!/usr/local/bin/perl use strict; use warnings; my $kSkipSeconds = 3600; my %epochs; while (<DATA>) { chomp; my ($ip, $epoch) = split /,/; next if ! $epoch; $epochs{$ip} = $epoch; } my @ip_array = qw(1.1.1.1 1.1.1.3 1.1.1.2); my $now = 1320640620; # time() for my $ip (@ip_array) { if (exists $epochs{$ip} && $epochs{$ip} + $kSkipSeconds > $now) { print "Skipping $ip\n"; next } print "Time to update $ip\n"; $epochs{$ip} = $now; } print "------------ updated epochs -------------\n"; print "$_,$epochs{$_}\n" for sort keys %epochs; __DATA__ 1.1.1.1,1320639902 1.1.1.3,1320640560 1.1.1.2,1320600900

    Prints:

    Skipping 1.1.1.1 Skipping 1.1.1.3 Time to update 1.1.1.2 ------------ updated epochs ------------- 1.1.1.1,1320639902 1.1.1.2,1320640620 1.1.1.3,1320640560
    True laziness is hard work

      Well I thought I had some stuff figured out and after another 15 hours of reading/testing I haven't gotten much further.

      I thought the ping part was working but now it seems intermittent, and I still can not get the foreach part to work. Basically I do not want to email a failure notive about the same failed ping to a host/IP until some time has passed, maybe 2-3 failures or something. While trying to ping once every 5 minutes. I have tried literally dozens of different ways to skip over the IP if it is on the email.list -- unless ($_ =~ my @eFile) -- was my last attempt but I can't get anything to work there.

      Any assistance is appreciated, thanks Sam.

      #!/usr/local/bin/perl use strict; use warnings; use Net::Ping; use Net::SMTP; my $from = 'from@email.com'; my $site = 'email.com'; my $smtp_host = 'smtp.email.com'; my $to = 'to@email.com'; my $smtp = Net::SMTP->new($smtp_host, Hello => $site); my $oFile = open(oFILE, ">", "output.file") or die("unable to write to + $!\n"); my $hFile = open(hFILE, "<", "host.file") or die("unable to open $!\n" +); my @ip_array = <hFILE>; chomp(@ip_array); my $eFile = open(eFILE, ">", "email.file") or die("unable to write to +$!\n"); my @efile = <eFILE>; chomp(@efile); sub email { $smtp->mail($from); $smtp->to($to); $smtp->data(); $smtp->datasend("To: $to\n"); $smtp->datasend("Subject: Ping failure notice.\n"); $smtp->datasend("\n"); $smtp->datasend("Ping failed on host $_\n"); $smtp->dataend; print eFILE ("$_\n"); } my $p = Net::Ping->new(); foreach (@ip_array) { if($p->ping($_)) { print oFILE ("$_ is responding to ping.\n"); } else { print oFILE ("$_ is NOT responding to ping.\n"); unless ($_ =~ my @eFile) { email(); } } } close(hFILE); close(oFILE); close(eFILE); $p->close(); $smtp->quit; #End of Code
      The files I am using: --host.file-- www.cnn.com 127.0.0.1 10.10.10.1 178.23.1.2 9.1.1.1> --email.file-- <empty> --output.file-- <empty>

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://936394]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (18)
As of 2014-04-18 18:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (471 votes), past polls