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

Thanks! I was stuck on this one. I knew where I was going wrong, just not what was going wrong. Now I can go to lunch. :) Obviously I am not the PERL master and I certinly appericate the suggestions to improve my coding. I didn't know about the LWP, sounds usefull. I am gonna have to read up on that one. Thanks again.
-Skip

Hi guys,

Hopenfully someone can help me with this one. Essentially the script below should run GETHTTP.EXE and save the output to a text file. It should then open the text file, dump it into an array and search for a particular string. If the string is found it should then write a line to a log file and end. If the string is not found it should run a little VBScript that will reconfigure a router. I think the problem is with the conditional statement that searches the array and creates the "$decide" var. Maybe I am doing something totally stupid, maybe it's just something small I am missing. If comeone could shed some light on this it would be greatly appericated. Thanks in advance. Here is the script. I commented it so it should be pretty self explanitory.
-Skip


# Get the all the values for current time ($Second, $Minute, $Hour, $Day, $Month, $Year, $WeekDay, $DayOfYear, $ +IsDST) = localtime(time); $RealYear = $Year + 1900; #Create proper format for year $RealMonth = $Month + 1; #Add 1 to month because PERL starts @ 0 # Add leading "0" to Miniute if less than 10 if($Minute < 10) { $Minute = "0". $Minute; } # Create a Log File open (fail_log,">>faillog.txt"); # Create Router Re-Configuration script run command $rtr_cfg="wscript.exe rtr-telnet.vbs"; # Create a var that holds the string to be found in the "gethttpbuff" +results $search="</html>"; # Create & run "GETHTTP.EXE" command. Redirect output to "gethttpbuff. +txt" $gethttp="gethttp.exe http://www.blahblahblah.com>gethttpbuff.txt"; system($gethttp); #it seems like the code below is what doesn't work right. if (&Search_Buff($decide == "1")){ &Site_Up; } else { &Site_Down; } # Sub to search gethttpbuff.txt for a string & return 0 or 1 sub Search_Buff { # Open hethttpbuff.txt file, create an array with the data & close fil +e. End if file is locked. open (gethttpbuff, "gethttpbuff.txt") || die("Could not open file!"); @array = <gethttpbuff>; close(gethttpbuff) # If search string is found make var equal to "1". If the search strin +g is not found make var equal to "0" foreach $line (@array) { if ($line =~ /$search/) { $decide = "1"; } else { $decide = "0"; } } sub Site_Up { # site is up print fail_log ($Hour); print fail_log (":"); print fail_log ($Minute); print fail_log ("-and all is well on "); print fail_log ($RealMonth); print fail_log ("-"); print fail_log ($Day); print fail_log ("-"); print fail_log ($RealYear); print fail_log ("\r\n"); } sub Site_Down { # Site is down print fail_log ("Blahblahblah.com has gone down! "); print fail_log ($Hour); print fail_log (":"); print fail_log ($Minute); print fail_log (" "); print fail_log ($RealMonth); print fail_log ("-"); print fail_log ($Day); print fail_log ("-"); print fail_log ($RealYear); print fail_log ("\r\n"); system($rtr_cfg); } }

Replies are listed 'Best First'.
Re: Problem Searching an array for a string... Please Help!
by holli (Abbot) on Feb 24, 2005 at 17:20 UTC
    A few thoughts.

    • use strict; it keeps you out of trouble
    • use warnings; it helps you diagnose errors
    • use POSIX; it has a nice function strftime() that is very capable of formatting dates/times
    • use LWP; keep perlish. There is no need for external programs, when there is a good module (LWP) for the same task.


    I rewrote your program, to give you an idea what i mean.
    use strict; use warnings; use LWP::Simple; use POSIX qw(strftime); my $address = $ARGV[0] or die "No address!"; # Create Router Re-Configuration script run command my $rtr_cfg="wscript.exe rtr-telnet.vbs"; # Create a var that holds the html and fill it my $html = get($address) || ""; # Create a Log File open (fail_log,">>faillog.txt"); if ( $html =~ /<\/html>/) { print fail_log strftime("%c - $address is up\n", localtime); } else { print fail_log strftime("%c - $address is down\n", localtime); system ($rtr_cfg); }

    I made the address to check a parameter, so you can call that script like:
    $ perl checksite.pl http://www.perlmonks.org

    Update:
    Added link to strftime reference for Win32


    holli, /regexed monk/
Re: Problem Searching an array for a string... Please Help!
by dragonchild (Archbishop) on Feb 24, 2005 at 16:56 UTC
    Change these lines as so:
    if (&Search_Buff($decide == "1")){ &Site_Up; } else { &Site_Down; } To: if( &Search_Buff ) { &Site_Up; } else { &Site_Down; }
    And change Search_Buff() to so:
    sub Search_Buff { open (gethttpbuff, "gethttpbuff.txt") || die("Could not open file! +"); @array = <gethttpbuff>; close(gethttpbuff) foreach $line (@array) { if ($line =~ /$search/) { return 1; } } return 0; }

    That should make everything work just fine.

    There are a number of other items you can do, such as adding use strict; to the top of your script to make it more robust, but that should get you going for now.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Problem Searching an array for a string... Please Help!
by Roy Johnson (Monsignor) on Feb 24, 2005 at 16:58 UTC
    You're setting $decide for each line you read, so it ends up telling you whether it was found in the last line; all other results were overwritten. Instead, you should set it to zero before reading, and only change it if you find the line.

    Caution: Contents may have been coded under pressure.
Re: Problem Searching an array for a string... Please Help!
by ikegami (Patriarch) on Feb 24, 2005 at 17:01 UTC

    Instead of system + redirection of output + reading text file, you could use backticks:
    $text = `gethttp.exe http://www.blahblahblah.com"`;

    But why don't you use the LWP library of modules instead of gethttp.exe. LWP comes with Perl and it's a tried and true way of getting web pages. LWP::Simple makes it extremely simple too.
    use LWP::Simple;
    $text = get("http://www.blahblahblah.com/")
    or die(...);

    If you want to split the text into lines:
    @array = $text =~ /([^\n]*\n)/g;

Re: Problem Searching an array for a string... Please Help!
by cbrandtbuffalo (Deacon) on Feb 24, 2005 at 16:58 UTC
    Couple of comments:
    • I would check the results of your 'open' and 'system' calls and all other such calls. It can be as simple as adding an 'or die' to the end of those lines. This avoid debugging in one area when a simple call is failing.
    • Consider dropping the global $decide variable and have the subroutine just return true or false. So you could do something like:
      if (&Search_Buff){ &Site_Up; } else { &Site_Down; } # And below: if ($line =~ /$search/) { return 1; } else { return 0; } }
      This might help you zero in on the issue a little easier.
Re: Problem Searching an array for a string... Please Help!
by davido (Cardinal) on Feb 24, 2005 at 16:58 UTC

    There are way too many problems here. Yes, one of them is your line "if( SearchBuff( $decide == 1 ) ) {...". Since you're using global variables, you would fix that problem by calling SearchBuff() first, and then say, "if( $decide == 1 ) {.....". But let me run down a list of things you really should do. Ok, they're not necessary, but may be good ideas if you want it done right:

    • Scrap this code and start over, writing a version that complies with strictures. In other words, use lexical variables, not globals, use strict, use warnings.
    • Use LWP::Simple. Why are you calling an external process to grab a webpage when you can just use LWP::Simple like this: "my $webpage = get( 'http://your.site.here' );".
    • No need to save the web page to disk if you use LWP::Simple. You can just start reading it from a scalar variable.
    • Did I mention using strict and using warnings?

    Dave

      * Scrap this code and start over, writing a version that complies with strictures. In other words, use lexical variables, not globals, use strict, use warnings.

      Congratulations! You just convinced someone that Perl is too much trouble to learn. A person took the trouble to register on this site and post an extremely coherent question, something that is a rarity in this place. Yet, you blatantly ignored the question being asked and imposed your own morals upon the questioner.

      For reference, the question was NOT one of the following:

      • How can I improve this script so that it is maintainable?
      • How can I improve my programming style?
      • How can I make this script more robust?

      The question actually was:

      How can I solve this immediate problem so that I can get my boss off my back and go to lunch already!

      Yet, you didn't help this person. You didn't suck them into the world of Perl with a free hit off the crack pipe. If we answer the question asked in a timely and effective manner, the OP will think "Gee, those Perlmonks guys really helped me out of a jam! Maybe I should hang out there more often." At that point, you can gently introduce him/her to strictures, CPAN, and the like. But, that time is not now.

      You, instead, gave them the impression that they had to build their own crackpipe from scratch, then go to Columbia to grow their own coca plants and refine it and ... how is that effective advocacy again?

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Problem Searching an array for a string... Please Help!
by JediWizard (Deacon) on Feb 24, 2005 at 17:02 UTC

    Ok I'm confused by something here...

    &Search_Buff($decide == "1")

    You are using a conditional statement as an argument to the &SearchBuff subroutine. But it appears that $decide which you are testing in the conditional is defined in &Search_Buff. This will not work because the conditional is being evaluated before the subroutine is executed. It looks like you want &Search_Buff to return a boolean value, and then test that. try something like this:

    if (&Search_Buff()){ &Site_Up; } else { &Site_Down; } # Sub to search gethttpbuff.txt for a string & return 0 or 1 sub Search_Buff { # Open hethttpbuff.txt file, create an array with the data & close +file. End if file is locked. open (gethttpbuff, "gethttpbuff.txt") || die("Could not open file!" +); @array = <gethttpbuff>; close(gethttpbuff) # If search string is found make var equal to "1". If the search st +ring is not found make var equal to "0" foreach $line (@array) { if ($line =~ /$search/) { return 1; } } return undef; # or return 0; }

    Update: Found a logicall flaw in my code. Correcting it.

    May the Force be with you
      Instead of return undef;, just use return;. That will work in list context as well as scalar/boolean context.

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.