Search code examples
perlperl-module

Regular expression to print a string from a command outpout


I have written a function that uses regex and prints the required string from a command output. The script works as expected. But it's does not support a dynamic output. currently, I use regex for "icmp" and "ok" and print the values. Now, type , destination and return code could change. There is a high chance that command doesn't return an output at all. How do I handle such scenarios ?

sub check_summary{

    my ($self) = @_;

    my $type  = 0;
    my $return_type = 0;

    my $ipsla = $self->{'ssh_obj'}->exec('show ip sla');

    foreach my $line( $ipsla) {
    if ( $line =~ m/(icmp)/ ) {
            $type = $1;
      }
      if ( $line =~ m/(OK)/ ) {
            $return_type = $1;
      }
    }

    INFO ($type,$return_type);
}


    command Ouptut :

    PSLAs Latest Operation Summary
    Codes: * active, ^ inactive, ~ pending

    ID           Type        Destination       Stats       Return      Last
                                               (ms)        Code        Run
    -----------------------------------------------------------------------
    *1           icmp      192.168.25.14    RTT=1       OK          1 second ago

Solution

  • Updated to some clarifications -- we need only the last line


    As if often the case, you don't need a regex to parse the output as shown. You have space-separated fields and can just split the line and pick the elements you need.

    We are told that the line of interest is the last line of the command output. Then we don't need the loop but can take the last element of the array with lines. It is still unclear how $ipsla contains the output -- as a multi-line string or perhaps as an arrayref. Since it is output of a command I'll treat it as a multi-line string, akin to what qx returns. Then, instead of the foreach loop

    my @lines = split '\n', $ipsla;      # if $ipsla is a multi-line string
    # my @lines = @$ipsla;               # if $ipsla is an arrayref
    
    pop @lines while $line[-1] !~ /\S/;  # remove possible empty lines at end
    
    my ($type, $return_type) = (split ' ', $lines[-1])[1,4];
    

    Here are some comments on the code. Let me know if more is needed.

    We can see in the shown output that the fields up to what we need have no spaces. So we can split the last line on white space, by split ' ', $lines[-1], and take the 2nd and 5th element (indices 1 and 4), by ( ... )[1,4]. These are our two needed values and we assign them.

    Just in case the output ends with empty lines we first remove them, by doing pop @lines as long as the last line has no non-space characters, while $lines[-1] !~ /\S/. That is the same as

    while ( $lines[-1] !~ /\S/ ) { pop @lines }
    

    Original version, edited for clarifications. It is also a valid way to do what is needed.

    I assume that data starts after the line with only dashes. Set a flag once that line is reached, process the line(s) if the flag is set. Given the rest of your code, the loop

    my $data_start;
    foreach (@lines) 
    {
        if (not $data_start) { 
            $data_start = 1 if /^\s* -+ \s*$/x;  # only dashes and optional spaces
        }
        else {
            my ($type, $return_type) = (split)[1,4];
            print "type: $type, return code: $return_type\n";
        }
    }
    

    This is a sketch until clarifications come. It also assumes that there are more lines than one.