从命令输出打印字符串的正则表达式

Regular expression to print a string from a command outpout

我编写了一个使用正则表达式并从命令输出中打印所需字符串的函数。 该脚本按预期工作。但它不支持动态输出。目前,我对 "icmp" 和 "ok" 使用正则表达式并打印值。现在, typedestinationreturn code 可能会改变。命令很有可能根本 return 没有输出。我该如何处理这种情况?

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 = ;
      }
      if ( $line =~ m/(OK)/ ) {
            $return_type = ;
      }
    }

    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

我不确定该命令输出的所有可能性,因此我的正则表达式可能需要调整。

我假设目标是获取变量中所有列的值。我选择使用列名作为散列键将值存储在散列中。我出于调试/演示目的打印了结果。

use strict;
use warnings;

sub check_summary {
    my ($self) = @_;

    my %results = map { ($_,undef) } qw(Code ID Type Destination Stats Return_Code Last_Run); # Put results in hash, use column names for keys, set values to undef.

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

    foreach my $line (@$ipsla) {
        chomp $line; # Remove newlines from last field

        if($line =~ /^([*^~])([0-9]+)\s+([a-z]+)\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\s+([[:alnum:]=]+)\s+([A-Z]+)\s+([^\s].*)$/) {
            $results{Code}        = ; # Code prefixing ID
            $results{ID}          = ;
            $results{Type}        = ;
            $results{Destination} = ;
            $results{Stats}       = ;
            $results{Return_Code} = ;
            $results{Last_Run}    = ;
        }
    }

    # Testing
    use Data::Dumper;
    print Dumper(\%results);
}

# Demonstrate
check_summary();

# Commented for testing
#INFO ($type,$return_type);

在提交的测试线上工作。

编辑: 正则表达式允许您指定模式而不是您尝试匹配的确切文本。这很强大,但有时很复杂。您需要阅读 Perl 正则表达式文档才能真正了解它们。

Perl 正则表达式还允许您捕获匹配的文本。这可以在一个模式中多次完成,这就是我们能够用一个表达式捕获所有列的方式。比赛进入编号变量...... 1美元 $2

已更新 一些说明——我们只需要最后一行


就像通常的情况一样,您不需要正则表达式来解析输出,如图所示。您有 space 分隔的字段,只需 split 行并选择您需要的元素即可。

我们被告知感兴趣的行是命令输出的最后一行。然后我们不需要循环,但可以用行获取数组的最后一个元素。目前还不清楚 $ipsla 如何包含输出——作为多行字符串或者可能作为数组引用。因为它是命令的输出,所以我将其视为多行字符串,类似于 qx returns。然后,而不是 foreach 循环

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];

这里是对代码的一些评论。让我知道是否需要更多。

我们可以在显示的输出中看到,我们需要的字段没有 spaces。因此,我们可以将白色的最后一行 space 拆分为 split ' ', $lines[-1],并将第二个和第五个元素(索引 1 和 4)拆分为 ( ... )[1,4]。这是我们需要的两个值,我们分配它们。

为了防止输出以空行结尾,我们首先删除它们,方法是 pop @lines 只要最后一行没有非 space 字符,while $lines[-1] !~ /\S/。也就是

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

原始版本,为澄清而编辑。这也是完成所需工作的有效方法。

我假设数据从只有破折号的行之后开始。到达该行后设置一个标志,如果设置了标志,则处理该行。鉴于您的其余代码,循环

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";
    }
}

在得到澄清之前,这是草图。它还假设行数多于一行。