我的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
答案 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