对你而言,这很简单......
我有一个类似的文件名列表;
fw_d.log.1.gz
through
fw_d.log.300.gz
当我使用下面的代码块时,它几乎按我想要的方式排序,但不完全。
#!/usr/bin/perl -w
my $basedir = "/var/log";
my @verdir = qw(fw_d);
my $fulldir;
my $configs;
my $combidir;
foreach $combidir (@verdir) {
$fulldir = "$basedir/$combidir";
opendir (DIR, $fulldir);
my @files = grep { $_ ne '.' && $_ ne '..' && $_ ne 'CVS' readdir DIR;
closedir (DIR);
@files1 = sort {$a cmp $b}(@files);
foreach my $configs (@files1) {
print "Checking $configs\n";
system("less $basedir/$combidir/$configs | grep \'.* Group = , Username = .* autheauthenticated.\' >> output.log" );
}
}
这是一个片段输出
Checking fw_d.log
Checking fw_d.log.1.gz
Checking fw_d.log.10.gz
Checking fw_d.log.100.gz
Checking fw_d.log.101.gz
Checking fw_d.log.102.gz
正如你所看到的,它几乎按照我的希望排序....有没有人有任何建议,无论是阅读,还是我可以使用的代码片段?
提前致谢。
史蒂夫。
答案 0 :(得分:21)
您可以使用Schartzian-transform:
my @sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, $_=~/(\d+)/] }
@files;
print Dumper \@sorted;
为Schwartzian-Transform和子程序
之间的比较添加了基准use Benchmark qw(:all);
# build list of files
my @files = map {'fw_d.log.'.int(rand()*1000).'.log' } 0 ..300;
my $count = -3;
my $r = cmpthese($count, {
'subname' => sub {
sub expand {
my $file=shift;
$file=~s{(\d+)}{sprintf "%04d", $1}eg;
return $file;
}
my @sorted = sort { expand($a) cmp expand($b) } @files;
},
'schwartzian' => sub {
my @sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, $_=~/(\d+)/] }
@files;
}
});
<强>结果:强>
Rate subname schwartzian
subname 21.2/s -- -92%
schwartzian 279/s 1215% --
Schwartzian-transform对300个文件的排序效率提高了13倍。
答案 1 :(得分:10)
问题在于代码执行了您告诉它的操作:按字母顺序对文件名进行排序。
您应该将sort { $a cmp $b }
替换为sort { expand($a) cmp expand($b) }
expand
:
sub expand
{ my $file=shift;
$file=~s{(\d+)}{sprintf "%04d", $1}eg; # expand all numbers to 4 digits
return $file;
}
答案 2 :(得分:6)
您可以尝试使用自定义排序功能:
sub sort_by_number {
$a =~ /(\d+)/;
$numa = $1;
$b =~ /(\d+)/;
$numb = $1;
return $numa <=> $numb;
}
然后排序如下:
@files1 = sort sort_by_number @files;
这将按@files
中的字符串对每个字符串中第一个数字的值进行排序。
答案 3 :(得分:1)
老问题,但还有答案尚未提及。
Sort::Naturally
为您做到了这一点:
按词法排序,但以数字方式对数字部分进行排序
#!/usr/bin/env perl
use strict;
use warnings;
use Sort::Naturally;
print nsort <DATA>;
__DATA__
fw_d.log
fw_d.log.101.gz
fw_d.log.1.gz
fw_d.log.10.gz
fw_d.log.100.gz
fw_d.log.2.gz
fw_d.log.102.gz
fw_d.log.12.gz
这个命令为:
fw_d.log
fw_d.log.1.gz
fw_d.log.2.gz
fw_d.log.10.gz
fw_d.log.12.gz
fw_d.log.100.gz
fw_d.log.101.gz
fw_d.log.102.gz