Re^2: Keeping only the $n newest files/directories in a diretory?
by Aristotle (Chancellor) on Apr 19, 2003 at 14:01 UTC
|
use File::Path;
sub purge {
my $n = shift; # 100, for example
my @newest_first = do {
my @dir = grep -d, </var/script/proc/*>;
my @age = map -M, @dir;
@dir[ sort { $age[$a] <=> $age[$b] } 0 .. $#dir ];
};
splice @newest_first, 0, $n;
rmtree \@newest_first, 0, 1 if @newest_first;
}
Makeshifts last the longest. | [reply] [d/l] |
Re: •Re: Keeping only the $n newest files/directories in a diretory?
by Juerd (Abbot) on Apr 19, 2003 at 13:05 UTC
|
(ST)
Is the ST really worth the effort here? On my system, in a directory with 20000 files, there is no noticable difference between
my @newest_first =
map $_->[0],
sort { $a->[1] <=> $b->[1] }
map [$_, -M],
<*>;
and
my @newest_first = sort { -M $a <=> -M $b } <*>;
while the first one took me much longer to type in.
Most directories on my systems don't even have twenty thousand files :)
Juerd
- http://juerd.nl/
- spamcollector_perlmonks@juerd.nl (do not use).
| [reply] [d/l] [select] |
|
|
Is the ST really worth the effort here?
I can understand the "premature optimization" argument here, but I can also understand it if merlyn (Randal Schwartz) types the top two lines of this optimization in his sleep, or at least with a single keystroke. ;)
While the /proc filesystem is not actually a filesystem as such, and a clone in /var would probably not have -M issues, either, the same pruning script would be useful in many different circumstances. If trying to run it on a slower link, such as an SMB mounted share across the corporate campus, on a per-hour cron job, I'd definitely want such an optimization.
-- [ e d @ h a l l e y . c c ]
| [reply] |
|
|
I can also understand it if merlyn (Randal Schwartz) types the top two lines of this optimization in his sleep
So do I. Which is the reason I commented. Yesterday someone said the same thing to me about another ST: is it really worth the effort and memory usage? What he said made sense: an ST uses a lot of memory and in many cases the win is too small to be relevant.
If trying to run it on a slower link, such as an SMB mounted share across the corporate campus
You may be right about this one. I don't know how SMB is implemented and whether any client side caching is (can be) done.
a per-hour cron job
In a per-hour cron job it doesn't matter. Even in a per-minute cron job, I'd argue that the difference between half a second and half a second is very small :)
Juerd
- http://juerd.nl/
- spamcollector_perlmonks@juerd.nl (do not use).
| [reply] |
Re: •Re: Keeping only the $n newest files/directories in a diretory?
by Anonymous Monk on Apr 19, 2003 at 11:47 UTC
|
I think this code is golfing at its best ;). It works but I don't understand it...
Could someone please explain the following part of merlyn's code:
my @newest_first =
map $_->[0],
sort { $a->[1] <=> $b->[1] }
map [$_, -M],
</var/script/proc/*>;
Thanks | [reply] [d/l] |
|
|
my @newest_first = sort { -M $a <=> -M $b } </var/script/proc/*>;
However, to sort, one must compare pairs of items, often comparing the same $a to many different $bs, and vice versa. All those -M checks take a lot of time.
Read a Schwartzian Transform like this starting with the last line.
<.../*> is a shorthand call to glob() that returns a list of files.
The map above that takes each filename and pairs it to its own -M check results. So you get a list of "foo.blah", timestamp pairs. The square brackets keep each pair in their own little referenced array.
The sort line sorts these pairs numerically descending by their second (index 1) element, the timestamps.
The map at the top will turn the sorted list of pairs into a list of filenames again, keeping the sorted order.
-- [ e d @ h a l l e y . c c ] | [reply] [d/l] |
|
|
All those -M checks take a lot of time.
On what antique system is that? Many simple filesystem operations are cached by the filesystem. System calls have overhead, but so does creating an array. And unless you have millions of files, you will probably not notice any difference in speed :)
Juerd
- http://juerd.nl/
- spamcollector_perlmonks@juerd.nl (do not use).
| [reply] |
|
|
Ok, reading it from the bottom up,
</var/script/proc/*>
Makes a list of files in that directory. It's then used
as the second argument to
map [$_, -M]
which, from that list, generates a 2nd-order list, each
element of which is a list containing in field one the
filename, and in field two the modification time
(-M is a test operator giving that -- it's default
parameter is $_). If you're a C Programmer, think
something like the following for each entry in that 2nd order list:
struct
{
char filename[FNSIZE];
int mtime; /* The date field -- modification time */
}
That structure is then used as an argument to
sort { $a->[1] <=> $b->[1] }
which sorts the first index of the 2nd-order list by the
date field. The results are then used as the 2nd argument to
map $_->[0]
which returns a 1d list containing just the filenames
(although they're sorted this time).
The results are then saved in @newest_first.
Code like the above can be intimidating unless you
know the map operator well. It's an extremely powerful
tool once you do though, and is one of the ways in which
Perl's expressiveness borrows from Lisp.
Hope this helps. | [reply] [d/l] [select] |
|
|
That's the Schwartzian Transform. I goes something like this:
</var/script/proc/*> will glob and return the list of file/directories in that folder.
each element is mapped into an array ref[ ] containing the original string and the last modified date -M
the list is sorted by the modification date which is the second element of the array ref, hence $a->[1]
then the first element of the array (which is the original folder name) is retrieved $_->[0] with another map
So in short, you get the list of folders, you build an array of arrays containing the folder name and the modification date, you sort by the modification date, and return only the folder names to use.
Update: :)
He who asks will be a fool for five minutes, but he who doesn't ask will remain a fool for life.
Chady | http://chady.net/
| [reply] [d/l] [select] |