输出不是按数字顺序排列的

时间:2018-02-17 13:53:31

标签: perl

我的Perl代码没有从数组中按数字顺序返回输出。

我有这个数字数组

my @luns = qw/
    393645
    393646
    393730
    393731
    393732
    393733
    414632
    433944
/;

我想执行一个命令并通过Perl中的管道读取输出,这样我就可以迭代@luns数组来搜索特定的值。

这是通过管道读取的命令的输出

primary-vds0     primary                                                  
/dev/dsk/c0txxxxxx393731d0s6
/dev/dsk/c0txxxxxx414632d0s6
/dev/dsk/c0txxxxxx393732d0s6
/dev/dsk/c0txxxxxx393733d0s6
/dev/dsk/c0txxxxxx393645d0s6
/dev/dsk/c0txxxxxx393646d0s6
/dev/dsk/c0txxxxxx393730d0s6
/dev/dsk/c0txxxxxx433944d0s6

这是我的剧本。

#!/bin/perl -w
use strict;

my @luns = qw/
    393645
    393646
    393730
    393731
    393732
    393733
    414632
    433944
/;

open(my $pipe, "ldm ls-services |") or die "Cannot open process: $!";

my $line;

while ( <$pipe> ) {

    foreach  $line ( @luns ) {

        if ( $_ =~ $line ) {

            print $_;
        }
    }
}

更新

我已经尝试了建议的评论,但它没有以数字方式返回。

while ( $line = <$pipe> ) {

    foreach ( @luns ) {

        if ($line =~ $_) {

            print "$_\n";
        }
    }
}

评论的输出是:

393731
414632
393732
393733
393645
393646
393730
433944

2 个答案:

答案 0 :(得分:1)

您只能使用两个嵌套循环来执行此操作,因为文件中的记录未进行排序。要解决此问题,您必须将匹配的行存储在数组中并对此数组进行排序。这样做的一个技巧很容易就是在每行的开头连接数字。然后,您只需使用字符串比较来对行进行排序:

use strict;
use warnings;

my @luns = qw/
393645
393646
393730
393731
393732
393733
414632
433944
/;

my @result;

while (my $line = <DATA>) {
    for (@luns) {
        push @result, sprintf("%07d%s", $_, $line) if ($line =~ $_);
    }
}

@result = map { substr $_, 7 } sort @result;

print join '', @result;

__DATA__
primary-vds0     primary                                                  
/dev/dsk/c0txxxxxx393731d0s6
/dev/dsk/c0txxxxxx414632d0s6
/dev/dsk/c0txxxxxx393732d0s6
/dev/dsk/c0txxxxxx393733d0s6
/dev/dsk/c0txxxxxx393645d0s6
/dev/dsk/c0txxxxxx393646d0s6
/dev/dsk/c0txxxxxx393730d0s6
/dev/dsk/c0txxxxxx433944d0s6

根据数字大小,您必须最终更改格式化字符串中前导零的数量和substr函数中的起始偏移量。

您也可以这样做,但这次使用数字比较:

my @result;

while (my $line = <DATA>) {
    for (@luns) {
        push @result, [ $_, $line ] if ($line =~ $_);
    }
}

@result = map { $_->[1] } sort { $a->[0] <=> $b->[0] } @result;

print join '', @result;

答案 1 :(得分:1)

最简单的方法是将命令的所有输出读入内存。这样可以多次搜索它以查看输出中是否出现任何@luns数组元素

如果@luns已预先排序,则输出的顺序相同。我已经添加了sort来确保它们是,但如果数字不总是六位数,那么你还必须使用前导零将它们填充到正确的长度;否则较短的LUN作为较长的子串会产生误报

在这里,我添加了一个测试,以确保如果LUN出现在命令输出中,那么它不能在其他数字之前或之后。这适用于您的样本数据,但我无法确定它是否通常是正确的

如果您有更新版本的List::Util,那么您可以使用any代替first

use strict;
use warnings;
use feature 'say';

use List::Util 'first';

my @luns = sort { $a <=>  $b } qw/
    393645
    393646
    393730
    393731
    393732
    393733
    414632
    433944
/;


my @data = <DATA>;
chomp @data;

for my $lun ( @luns ) {

    say $lun if first { /(?<!\d)$lun(?!\d)/ } @data;
}


__DATA__
primary-vds0     primary                                                  
/dev/dsk/c0txxxxxx393731d0s6
/dev/dsk/c0txxxxxx414632d0s6
/dev/dsk/c0txxxxxx393732d0s6
/dev/dsk/c0txxxxxx393733d0s6
/dev/dsk/c0txxxxxx393645d0s6
/dev/dsk/c0txxxxxx393646d0s6
/dev/dsk/c0txxxxxx393730d0s6
/dev/dsk/c0txxxxxx433944d0s6

输出

393645
393646
393730
393731
393732
393733
414632
433944