|
|
 |
 |
 |
 |
Perl Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
sort?
Greeting: I have the following code to sort an array of dirs/files: @sorted = sort { -M $b <=> -M $a } @logfile; foreach $lastfilemod (@sorted) { $dir = (dirname $lastfilemod); if (! exists $srt{$dir} ) { push(@srtlist, $lastfilemod); $srt{$dir} = 1; } } The @logfile looks like: /dir/dir/file1 /dir/dir/file2 /dir/dir2/file1 ... What I was trying to do is have @sorted list the files by last modified and then I could print out each file last modified in one per directory. However the sort isn't working correctly and I'm not getting the last file modified for some directories. Could anyone point out what I'm doing wrong? Thanks in advance for any help! Tom
On May 24, 6:02 pm, g41@motorola.com wrote:
> Greeting: > I have the following code to sort an array of dirs/files: > @sorted = sort { -M $b <=> -M $a } @logfile; > foreach $lastfilemod (@sorted) { > $dir = (dirname $lastfilemod); > if (! exists $srt{$dir} ) { > push(@srtlist, $lastfilemod); > $srt{$dir} = 1; > } > } > The @logfile looks like: > /dir/dir/file1 > /dir/dir/file2 > /dir/dir2/file1
Have you checked that the values of the entries in @logfile are actually the _exact_ names of files that exist and that you have permission to read the attributes of? Are you sure that, for example, you don't have newline characters appended? I'd to a transform and check -M worked. my @sorted = map { $_->[0] } sort { $b->[1] <=> $a->[1] } @logfile;
> ... > What I was trying to do is have @sorted list the files by last > modified and then I could print out each file last modified in one per > directory. However the sort isn't working correctly and I'm not > getting the last file modified for some directories. Could anyone > point out what I'm doing wrong? > Thanks in advance for any help! > Tom
On May 24, 6:32 pm, Brian McCauley <nobul@gmail.com> wrote:
> On May 24, 6:02 pm, g41 @motorola.com wrote: > > Greeting: > > I have the following code to sort an array of dirs/files: > > @sorted = sort { -M $b <=> -M $a } @logfile; > > foreach $lastfilemod (@sorted) { > > $dir = (dirname $lastfilemod); > > if (! exists $srt{$dir} ) { > > push(@srtlist, $lastfilemod); > > $srt{$dir} = 1; > > } > > } > > The @logfile looks like: > > /dir/dir/file1 > > /dir/dir/file2 > > /dir/dir2/file1 > Have you checked that the values of the entries in @logfile are > actually the _exact_ names of files that exist and that you have > permission to read the attributes of? Are you sure that, for example, > you don't have newline characters appended? > I'd to a transform and check -M worked. > my @sorted = > map { $_->[0] } > sort { $b->[1] <=> $a->[1] } > @logfile;
Opps hit send before I finished typing... # Untested my @sorted = map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { my $mod = -M; if ( defined $mod ) { [ $_, $mod ]; else { warn "$_: $!\n"; (); } } @logfile;
On May 24, 1:02 pm, g41@motorola.com wrote:
> Greeting: > I have the following code to sort an array of dirs/files: > @sorted = sort { -M $b <=> -M $a } @logfile; > foreach $lastfilemod (@sorted) { > $dir = (dirname $lastfilemod); > if (! exists $srt{$dir} ) { > push(@srtlist, $lastfilemod); > $srt{$dir} = 1; > } > } > The @logfile looks like: > /dir/dir/file1 > /dir/dir/file2 > /dir/dir2/file1 > ... > What I was trying to do is have @sorted list the files by last > modified and then I could print out each file last modified in one per > directory. However the sort isn't working correctly and I'm not > getting the last file modified for some directories. Could anyone > point out what I'm doing wrong?
I think you have your sort backwards, for one. -M returns the number of days since the file was modified. You're sorting the resutls of -M in descending numerical order. That is, largest first. So the file with the LARGEST number of days since it was modified comes first. The file with the largest number of days since modification is the least recently modified, not most recently. Once you get this working, I also rather strongly suggest you not use the file-comparison operators in a sort subroutine. It's very ineffient, as you're doing a stat() call on every file in your list multiple times. Instead, use a Schwartzian transform: my @sorted = map { $_->[0] } sort { $a->[1] <=> $b->[1] } map { [ $_, -M $_ ] } @logfile; Paul Lalli
In article <1180026173.627588.321@q75g2000hsh.googlegroups.com>, <g41@motorola.com> wrote: : I have the following code to sort an array of dirs/files: : : @sorted = sort { -M $b <=> -M $a } @logfile; : foreach $lastfilemod (@sorted) { : $dir = (dirname $lastfilemod); : if (! exists $srt{$dir} ) { : push(@srtlist, $lastfilemod); : $srt{$dir} = 1; : } : } : : The @logfile looks like: : : /dir/dir/file1 : /dir/dir/file2 : /dir/dir2/file1 : ... : : What I was trying to do is have @sorted list the files by last : modified and then I could print out each file last modified in one per : directory. However the sort isn't working correctly and I'm not : getting the last file modified for some directories. Could anyone : point out what I'm doing wrong? For each file, remember it if it was modified more recently than the current frontrunner for the file's parent directory: $ cat try #! /usr/bin/perl use warnings; use strict; use File::Basename; sub filename { $_[0]->[0] } sub modified { $_[0]->[1] } my %last; for (`find /tmp -type f 2>/dev/null`) { chomp; my $dir = dirname $_; my $mod = -M $_; $last{$dir} = [ basename($_), $mod ] if !$last{$dir} || $mod > modified $last{$dir}; } foreach my $dir (sort keys %last) { print "$dir: ", filename($last{$dir}), "\n"; } $ ./try /tmp: sh-thd-1172576387 /tmp/exportfig: restorefig.m /tmp/shared: .Xdefaults /tmp/split-sequence: split-sequence.lisp Hope this helps, Greg -- The idea that the vote of a people, no matter how nearly unanimous, makes or creates or determines what is right or just becomes as absurd and unacceptable as the idea that right and justice are simply whatever a king says they are. -- Robert Welch
Hi All: Thanks for all the responces! I found that -M doesn't give the granularity I needed. Some of the files were only seconds away for the other. I changed to the following: use File::stat; @sorted = sort { (stat($b)->mtime) <=> (stat($a)->mtime) } @logfile; foreach $lastfilemod (@sorted) { $dir = (dirname $lastfilemod); if (! exists $srt{$dir} ) { push(@srtlist, $lastfilemod); $srt{$dir} = 1; } }
Hi All: Thanks for all the responces! I found that the -M doesn't give the granularity I need. Some of the files were only seconds apart. I changed to the following: use File::stat; @sorted = sort { (stat($b)->mtime) <=> (stat($a)->mtime) } @logfile; foreach $lastfilemod (@sorted) { $dir = (dirname $lastfilemod); if (! exists $srt{$dir} ) { push(@srtlist, $lastfilemod); $srt{$dir} = 1; } } This got just what I was looking for. Thanks again for all the replys! Tom
On May 24, 2:28 pm, g41@motorola.com wrote: > Thanks for all the responces! I found that -M doesn't give the > granularity I needed.
I'm sorry, what?! [14:43:46] ~/tmp $ touch file.txt [14:43:52] ~/tmp $ perl -le'print -M "file.txt"' 0.000115740740740741 Exactly how much more granularity do you need?! Paul Lalli Some of the files were only seconds away for the > other. I changed to the following: > use File::stat; > @sorted = sort { (stat($b)->mtime) <=> (stat($a)->mtime) } > @logfile;
The reason this works and your other one didn't is because you're now comparing the last modified times as seconds sine the epoch, not days since last modified. So NOW, your descending numerical sort is correct. The file with the greatest seconds since the epoch is in fact the most recently modified. Compare and contrast with the file with the greatest days since last modified. * If you had just swapped $a and $b in your original, it would have been fine. Paul Lalli * Here's an example. Presuming we're running at 14:55:00 on May 24, 2007.... file1 - last modified Jan 1, 1970 00:00:00 file2 - last modified May 23, 2007, 14:55:00 file3 - last modified May 24, 2007, 14:55:00 -M file1 returns 13657.7849421296 -M file2 returns 1 -M file3 returns 0 stat(file1)->mtime returns 0 stat(file2)->mtime returns 1179946500 stat(file3)->mtime returns 1180032900 Do you see now what you did wrong the first time?
g41 @motorola.com wrote: > Hi All: > Thanks for all the responces! I found that the -M doesn't give the > granularity I need. Some of the files were only seconds apart.
So what, pray tell, do you think -M actually returns? It is _NOT_ the integer number of days of age. Proof that -M has all the granularity you need: linux% foreach n (0 1 2 3) foreach? touch -d "2-Jan-1970 12:00:0$n" $n foreach? end linux% ls -l ? -rw-r--r-- 1 jms jms 0 Jan 2 1970 0 -rw-r--r-- 1 jms jms 0 Jan 2 1970 1 -rw-r--r-- 1 jms jms 0 Jan 2 1970 2 -rw-r--r-- 1 jms jms 0 Jan 2 1970 3 linux% perl -le 'print "file $_ has -M = ", -M $_ for @ARGV' ? file 0 has -M = 13661.9331481481 file 1 has -M = 13661.9331365741 file 2 has -M = 13661.933125 file 3 has -M = 13661.9331134259 1/(24*60*60) = 0.00001157407 Where did you come up with the idea that -M is not suitable? -Joe
|
 |
 |
 |
 |
|