nims nims - 11 months ago 38
Perl Question

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,

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 RTT=1 OK 1 second ago

Answer Source

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 not clear 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.