On Mon, Jan 12, 2009 at 16:59, Harry Putnam <rea...@newsguy.com> wrote:
> I want to do something like this but with perl:
>
> rm -f $(ls -lt|sed -n '6,$p')
>
> so that the five newest files are always left.
>
> Is there some short way to get that effect in perl?
>
> Or do I have to analyze each file with stat or something?
snip

In the end, someone has to stat each file, but you should be able to
get what you want like this:

my @files =
    map { $_->[1] }
    sort { $b->[0] <=> $a->[0] }
    map { -f $_ ? [-M _, $_] : () }
    <*>;

pop @files for 1 .. 5; #some would use splice here

for my $file (@files) {
    unlink $file or warn "could not remove $file: $!";
}

The first part is a Schwartzian Transform.  It is used because we
don't want to have to keep stat'ing the files during the sort.  So we

1. take the list of files in the current directory (<*>)
2. create a list of arrayrefs that contain the relative age of the
each regular file and its file name (map { -f $_ ? [-M _, $_] : () })
3. sort on the relative ages of the files (sort { $b->[0] <=> $a->[0] })
4. and, finally, recover only the file names

It is important to note that the _ is not a typo.  It is a special
filehandle that refers to the last stat'ed file.  There is no reason
to call stat a second time to get the relative age of the file since
we know it from the first call to -f (the file test operators are just
fancy stat calls).  For more info read about the stat function*, the
filetest operators**, and filetest pragma***.

If you are not already familiar with the map**** and sort*****
functions then you might want to read about them as well.  Sort is
fairly obvious, but map can take some getting used to.  Its function
is to take a list and return a transformed list.  An easy example
would be to find all of the squares of 1 through 5:

my @squares = map { $_ * $_ } 1 .. 5; #will be (1, 4, 9, 16, 25)

You can make a longer list than the input by producing a list inside the map:

my %squares = map { $_, $_ * $_ } 1 .. 5; #will be 1, 1, 2, 4, 3, 9,
4, 16, 5, 25

You can also produce a smaller list by producing an empty list when
you want to discard an item:

my @dirs = map { -d $_ ? $_ : () } <*>;

In this specific case we can use map's cousin grep******:

my @dirs = grep { -d $_ } <*>;


* http://perldoc.perl.org/functions/stat.html
** http://perldoc.perl.org/functions/-X.html
*** http://perldoc.perl.org/filetest.html
**** http://perldoc.perl.org/functions/map.html
***** http://perldoc.perl.org/functions/sort.html
****** http://perldoc.perl.org/functions/grep.html

-- 
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.

-- 
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to