Perl 输出不按数字顺序

Perl 输出不按数字顺序,perl,Perl,我的Perl代码没有从数组中以数字顺序返回输出 我有这个数字数组 my @luns = qw/ 393645 393646 393730 393731 393732 393733 414632 433944 /; 我想执行一个命令并通过Perl中的管道读取输出,这样我就可以迭代@luns数组来搜索特定的值 这是通过管道读取的命令的输出 primary-vds0 primary

我的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 $_;
        }
    }
}

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

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

最简单的方法是将命令的所有输出读入内存。通过这种方式,可以对其进行多次搜索,以查看是否有任何
@luns
数组元素出现在输出中

如果对
@luns
进行了预排序,则输出顺序相同。我添加了一个
sort
调用,以确保它们是正确的,但是如果数字不总是六位数长,那么您还必须使用前导零将它们填充到正确的长度;否则,作为较长LUN的子字符串的较短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

由于$位于foreach循环内,因此它不再是文件的一行,而是数组的一个值。简而言之,
$\u=~$line
$line=~$line
相同。改为写:
while($line=){foreach(@luns){if($line=~$){
也可以使用条件
索引($line,$)!=-1
代替
$line=~$\ucode>@Casimir et Hippolyte查看我的更新。“你不能只使用两个嵌套循环,因为文件中的记录没有排序”但是,
@luns
的内容是经过排序的,因此,如果您在最外层的循环中迭代数组,输出也将被排序。必须有一种方法可以扫描每个LUN的整个输入数据,并且
ldm
命令的输出应该足够小,可以将其读入数组。
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
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;
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