perlchomp

Perl Comparison string


I am using the below script to compare the output I receive from SNMPGet. The output is in string format and shown below.

SnmpGet v1.01 - Copyright (C) 2009 SnmpSoft Company
[ More useful network tools on http://www.snmpsoft.com ]

OID=.1.3.6.1.4.1.9002.1.3.65.205.166.82.0
Type=Gauge32
Value=3

I need to compare the value in the 6th line of the output (Value=3)

use strict;
use warnings;
my $cmd="D:\\Perl32\\bin\\SnmpGet.exe -r:X.X.X.X -v:3 -sn:Solar -ap:SHA -aw:50 -pp:AES128 -pw:W1nD% -o:1.3.6.1.4.1.9002.1.3.65.205.166.82.0 -t:20";
my $snmpvalue0;
my $msg0;
open(Row2Stat,"$cmd |") || die ("Could not read the pipe\n");
$snmpvalue0 = <Row2Stat>;
close(Row2Stat);
if( $snmpvalue0 eq "Value=3")
{
    $msg0="active";
    $snmpvalue0 ="3";
}
elsif( $snmpvalue0 eq "Value=4" )
{
    $msg0="destroy";
    $snmpvalue0 ="4";
}
print "\nStatistic.Name:$snmpvalue0";
print "\nMessage.Name:$msg0";

I believe I have to use chomp and I am running into an issue with the syntax.Is there a way, I can use it to compare with the 6th line which I have in the output (Value=3)


Solution

  • Instead of

    if ($snmpvalue0 = <Row2Stat>)
    

    what reads one line of command's output, you want

    while (my $snmpvalue0 = <Row2Stat>) {
        # process $snmpvalue0
    }
    

    so to read one by one all lines that the command returns. As you read, for each line look for Value=N (N for a-number) and parse the line with it to get the number out of it.

    Probably easiest in Perl is by using a regex, to both detect that pattern in a line and extract the number from it, for example by

    $snmpvalue0 =~ /Value=([0-9]+)/;
    

    Then on a line with Value=N this will match and the the number gets captured and placed into a variable $1. Now one can use this in a number of ways

    while (my $snmpvalue0 = <Row2Stat>) {
        if ( $snmpvalue0 =~ /Value=([0-9]+)/ ) {
            my $val = $1;  # or use $1 directly
        }
    }
    

    or match and assign the captured number (or undef if no match) in the same statement, then test

    while (my $snmpvalue0 = <Row2Stat>) {
        my ($val) = $snmpvalue0 =~ /Value=([0-9]+)/;
        if ($val) {   
            # use $val 
        }
    }
    

    or match, assign, and test in one statement

    while (my $snmpvalue0 = <Row2Stat>) {
        if ( my ($val) = $snmpvalue0 =~ /Value=([0-9]+)/ ) { 
            # use $val 
        }
    }
    

    We need parentheses around $val to provide the "list context" in which the captured value is returned (and not just true/false). See perlretut, or your favorite text on regex.


    A comment on that open and pipe. Better use a lexical variable for a file handle, and the three-argument form of open

    open(my $Row2Stat,'|-', $cmd) or die "Can't open the pipe: $!";
    

    Also note the actual error $! put in die message, so to see why open failed (if it does).

    (In principle it is better yet to split the command into a list of words and use that in open, but on Windows the list form is "emulated" so perhaps better not do it; see open in perlport)

    Finally, once you are done reading absolutely do explicitly close that pipe,and test for errors

    open my $fh, '|-', $cmd or die ...
    while (my $line = <$fh>)       ...
    
    close $fh      # waits for command to finish
        or warn $! ? "Error closing command's pipe: $!"
                   : "Exit status $? from command";
    

    There are other options, of course, depending on the data that you get and/or may get.

    For one, one can take anything that comes with Value=

    /Value=(\S+)/
    

    and then analyze the captured text. Whether this is more suitable depends on how SnmpGet.exe operates and what returns are possible.

    Can it return a code/word with Value=... other than a number? A decimal number? Or is it always an integer? Can there be nothing after = -- perhaps to indicate an error/failure of some sort? -- then we'd need (\S*) for the pattern to match (and capture an empty string). Etc

    Another option is to capture and parse (analyze) -- both sides of =, either with

    /([^=]+)=(\S)/  # $1 and $2 populated when there is a match, or
    
    my ($key, $val) = /([^=]+)=(\S)/;
    

    or using split

    my ($all_before_eq, $all_after_eq) = split $line, /=/, 2; 
    

    (But note that $all_after_eq is now the whole rest of the line.)

    There are other variations -- should the pattern be anchored to the beginning of the line (/^.../) or not? Should one allow for possible spaces (/Value\s*=\s*.../)? Etc.

    These and similar details reflect a lot about the approach and policies related to the code and tolerance for variations in what is expected and accepted. Please consider and study your data and choose the parsing approach and details carefully.