views:

95

answers:

5

I want to replicate ls -ltr unix command in perl script without using backticks, exec or system. Following script is working:

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;

Question: How can I combine the sort and grep in a single line so that I can do away with @latest2 ?

+2  A: 

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

jkramer
+1  A: 

Like this:

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

Perl pipelined commands follow the right-to-left direction of the assignment operator. So you kind of have to think backwards. It is the operation that is done closest to the equals sign that it done first.

Of course, it is so second nature to me now, that I rarely think about how "backwords" it might seem. However if you grep first and then sort, you're going to have a more compressed sort, and as the best sorts are semi-quadratic, reducing the amount of items you are going to sort makes a lot of sense.

As handles are closed when they go out of scope, you can just do this:

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

As you are using a glob to do this, you don't need to open the directory handle. But if you were, you can do it like this:

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

The solutions presented here already are o.k. but probably may get slow if used on a very large directory, the sort function would then repeatedly apply -M on the same files over and over again. Therefore, one could use a Schwartzian Transform to avoid this (if necessary):

...

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

...

Regards

rbo

rubber boots
Nïce;) The *Memoize* module might also be helpful in similar situations
hlynur
A: 

Unix ls has been implemented in Perl as part of the Perl Power Tools (ls) suite .

Many other Unix commands are also implemented.

toolic