2010-08-11 55 views
1

我想在perl脚本中复制ls -ltr unix命令而不使用反引号,exec或system。以下脚本正在工作:ls -ltr in perl

use strict; 
my $dir="/abc/xyz/log"; 
opendir(DIR, $dir) or die "Can not open $dir $!"; 
my @latest = (sort {-M $b <=> -M $a} <$dir/*>); 
my @latest2= grep { !/^\./ && -f "$_"} @latest; 
closedir DIR; 

问题:如何将排序和grep整合到一行中,以便我可以取消@ latest2?

+1

你有没有考虑过使用管道? – Lazarus 2010-08-11 13:07:13

+0

你能解释我怎么用管子?这将有所帮助。 – Sachin 2010-08-11 13:09:27

+0

@Lazarus,对于所有实际用途,这不就是反引号,执行或系统吗? – 2010-08-11 13:13:29

回答

2

my @latest = grep { !/^\./ && -f "$_"} (sort {-M $b <=> -M $a} <$dir/*>);

1

像这样:

my @latest = grep { !/^\./ && -f "$_"} (sort {-M $b <=> -M $a} <$dir/*>); 
0

Perl的流水线命令遵循赋值运算符从右到左的方向。所以你必须反思。这是完成最接近到它首先完成的等号的操作。

当然,现在对我而言,这是如此的第二性质,我很少考虑它可能看起来像什么“backwords”。但是,如果你先grep然后排序,那么你将会有更多的压缩排序,并且由于最好的排序是半二次的,所以减少你要排序的项目数量是非常有意义的。

,当他们走出去的范围手柄闭合,你可以这样做:

my @list 
    = sort {-M $b <=> -M $a} 
     grep { !/^\./ && -f "$_"} 
     <$dir/*> 
    ; 

当你使用的是glob要做到这一点,你并不需要打开目录句柄。但如果你是,你可以这样做:

my @list = sort ... grep ... 
      do { opendir(my $dh, $dir) or die "Cannot open '$dir': $!"; 
       readdir($dh) 
       }; 
10

这里提出的解决方案已经是o.k.但是如果在非常大的目录中使用,可能会变得很慢,那么sort函数会反复将-M重复应用于相同的文件。因此,人们可以使用 Schwartzian Transform避免这种情况(如有必要):

... 

my @sorted_fnames = 
     map $_->[0]  ,   # ↑ extract file names 
     sort { $a->[1] <=> $b->[1] } # ↑ sort ascending after mdate 
     map [$_, -M $_] ,   # ↑ pre-build list for sorting 
     grep ! /^\.\.?$/ ,   # ↑ extract file names except ./.. 
     readdir $dirhandle;    # ↑ read directory entries 

... 

问候

RBO

+1

Nisy;)* Memoize *模块也可能有助于类似的情况 – hlynur 2010-08-11 13:55:39