Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

using File::Find to find recently-installed modules

by Aldebaran (Curate)
on Jun 24, 2016 at 05:11 UTC ( [id://1166461]=perlquestion: print w/replies, xml ) Need Help??

Aldebaran has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I'm working through the exercises in the alpaca book, to wit where the castaways have specified a local::lib and now seek to write a script that gives useful time data associated with these files. My needs are not exactly what the book calls for in any one exercise but range over several, so I used File::Find for the first time instead of relying on windows explorer to tell me where and what things are. (Uggh.)

In the last couple weeks, I've torn out and replaced an overgrown perl install with this machine, so I wanted to pay some attention to make this install a bit more robust, and consequently have strawberry perl. I had a false start on local::lib, which I hope won't matter in the scheme of things, which I only state so that no one could say "why didn't you tell us you had a screwy, abortive, previous attempt at creating a local::lib?" It may matter, may not. That's part of what I'm learning. Here's what I have now:

use strict; use warnings; use utf8; use 5.014; use File::Find; my @directories_to_search = ('.', 'C:\Users\Fred\Desktop'); my @files; find( \&find_module, @directories_to_search ); sub find_module { if ( $_ =~ m/.pm$/ ) { my $name = $File::Find::name; push( @files, $name ); } } for my $file (@files) { my $mtime = (stat $file)[9]; # mtime via slice my $when = localtime $mtime; print "$when: $file\n"; }

Output:

... Thu Apr 30 10:24:40 2015: ./alpaca/template_stuff/html1.pm Sun Jun 5 14:32:45 2016: ./alpaca/template_stuff/html2.pm Sun Jun 5 14:08:18 2016: ./alpaca/template_stuff/html3.pm Thu Apr 30 10:24:40 2015: ./alpaca/template_stuff/utils1.pm Wed Jun 9 08:59:19 2010: ./perl5/lib/perl5/HTML/ElementGlob.pm Wed Jun 9 08:24:01 2010: ./perl5/lib/perl5/HTML/ElementRaw.pm Wed Jun 9 13:56:58 2010: ./perl5/lib/perl5/HTML/ElementSuper.pm Wed Jun 9 16:17:31 2010: ./perl5/lib/perl5/HTML/ElementTable.pm Thu Feb 15 07:35:15 2007: ./perl5/lib/perl5/HTML/Extract.pm Thu May 21 09:22:21 2015: ./perl5/lib/perl5/HTML/TableExtract.pm Mon Nov 1 07:04:16 2010: ./perl5/lib/perl5/Prompt/Timeout.pm Wed Jun 24 04:07:26 2009: ./perl5/lib/perl5/WWW/Mechanize/GZip.pm

It appears that cpan modules are getting stored in a place that seems to have 'perl5' in it twice. Hope that's okay. Scripts are able to find these so far. Otherwise, I see that, unlike the professor, mtime is not what I'm looking for, as the time I'm interested in is when they got saved to this locale. Is there a perl way to make sure I own these? (The dot is 'Documents', so I would think so indeed.)

My quest for a "born-on" timestamp continued with reading up on stat, so I worked up versions of the same material using atime and ctime. I don't think I see the difference between the two, so I wonder which one works better as a "born-on" date in this context:

use strict; use warnings; use utf8; use 5.014; use File::Find; my @directories_to_search = ('.', 'C:\Users\Fred\Desktop'); my @files; find( \&find_module, @directories_to_search ); my @time =localtime; say "local time is @time"; sub find_module { if ( $_ =~ m/.pm$/ ) { my $name = $File::Find::name; push( @files, $name ); } } for my $file (@files) { my $atime = (stat $file)[8]; # atime via slice my $when = localtime $atime; print "$when: $file\n"; }

atime output:

local time is 13 44 19 23 5 116 4 174 1 Mon Jun 13 19:12:19 2016: ./alpaca/template_stuff/html1.pm Mon Jun 13 19:12:19 2016: ./alpaca/template_stuff/html2.pm Mon Jun 13 19:12:19 2016: ./alpaca/template_stuff/html3.pm Mon Jun 13 19:12:19 2016: ./alpaca/template_stuff/utils1.pm ... Wed Jun 22 22:09:13 2016: ./perl5/lib/perl5/HTML/ElementGlob.pm Wed Jun 22 22:09:13 2016: ./perl5/lib/perl5/HTML/ElementRaw.pm Wed Jun 22 22:09:13 2016: ./perl5/lib/perl5/HTML/ElementSuper.pm Wed Jun 22 22:09:13 2016: ./perl5/lib/perl5/HTML/ElementTable.pm Wed Jun 22 22:07:17 2016: ./perl5/lib/perl5/HTML/Extract.pm Wed Jun 22 22:08:24 2016: ./perl5/lib/perl5/HTML/TableExtract.pm Wed Jun 22 22:12:21 2016: ./perl5/lib/perl5/Prompt/Timeout.pm Wed Jun 22 22:06:40 2016: ./perl5/lib/perl5/WWW/Mechanize/GZip.pm

This has the useful information I need, and seems the same on inspection as the same script with the change of

 my $ctime = (stat $file)[10];

My intent is to make comparisons of time values part of the search criteria. I found many of these values astonishing and unexpected compared to the reading. Again my final question for moving forward is whether atime or ctime would serve as a better born-on date. Thank you for your comment.

Replies are listed 'Best First'.
Re: using File::Find to find recently-installed modules
by stevieb (Canon) on Jun 24, 2016 at 10:52 UTC

    I don't believe finding file creation time is possible with Perl. Not only that, it'll be very file-system dependent. If I understand what you're trying to do, mtime will likely be your best bet, as the only time you're updating a .pm Perl Module file is when you're upgrading it anyway, so that would technically be 'creation'.

    This may help a bit: difference between mtime, ctime and atime.

      Thanks for your response, steve, I'd been reading you in a different thread on issues in _Intermediate Perl_: http://www.perlmonks.org/?node_id=1165617

      The XY direction I would like to take your response in is using timestamps to figure out this thing that I've just created:

      C:\Users\Fred\Documents\alpaca>cd template_stuff C:\Users\Fred\Documents\alpaca\template_stuff>module-starter --module= +html3 --au thor="Gilligan" -email="gilligan@minnow.com" --verbose Created html3 Created html3\lib Created html3\lib\html3.pm Created html3\t Created html3\t\pod-coverage.t Created html3\t\00-load.t Created html3\t\pod.t Created html3\t\manifest.t Created html3\xt Created html3\xt\boilerplate.t Created html3\ignore.txt Created html3\Makefile.PL Created html3\Changes Created html3\README Added to MANIFEST: Changes Added to MANIFEST: ignore.txt Added to MANIFEST: lib/html3.pm Added to MANIFEST: Makefile.PL Added to MANIFEST: MANIFEST Added to MANIFEST: README Added to MANIFEST: t/00-load.t Added to MANIFEST: t/manifest.t Added to MANIFEST: t/pod-coverage.t Added to MANIFEST: t/pod.t Added to MANIFEST: xt/boilerplate.t Created html3\MANIFEST Created starter directories and files C:\Users\Fred\Documents\alpaca\template_stuff>

      Results:

      C:\Users\Fred\Documents\alpaca\template_stuff\html3>dir Volume in drive C is Windows8_OS Volume Serial Number is 3052-CD20 Directory of C:\Users\Fred\Documents\alpaca\template_stuff\html3 06/24/2016 08:30 PM <DIR> . 06/24/2016 08:30 PM <DIR> .. 06/24/2016 08:30 PM 110 Changes 06/24/2016 08:30 PM 198 ignore.txt 06/24/2016 10:41 PM <DIR> lib 06/24/2016 08:30 PM 701 Makefile.PL 06/24/2016 08:30 PM 129 MANIFEST 06/24/2016 08:30 PM 3,275 README 06/24/2016 08:30 PM <DIR> t 06/24/2016 08:30 PM <DIR> xt 5 File(s) 4,413 bytes 5 Dir(s) 50,578,202,624 bytes free C:\Users\Fred\Documents\alpaca\template_stuff\html3>cd lib C:\Users\Fred\Documents\alpaca\template_stuff\html3\lib>dir Volume in drive C is Windows8_OS Volume Serial Number is 3052-CD20 Directory of C:\Users\Fred\Documents\alpaca\template_stuff\html3\lib 06/24/2016 10:41 PM <DIR> . 06/24/2016 10:41 PM <DIR> .. 06/24/2016 08:30 PM 3,571 html3.pm 06/24/2016 10:41 PM 100 monks1.txt 2 File(s) 3,671 bytes 2 Dir(s) 50,578,989,056 bytes free C:\Users\Fred\Documents\alpaca\template_stuff\html3\lib>

      Question Y might be: why create a distribution? I've read that book cover to cover scratching my head about that, thinking that there's a good reason for the effort. Also know that I burned the way I used to create workspaces, ergo looking for new methods.

      Question Z might be: how do I get a brand new shiny version of the code I had, using this toolchain, before I screwed it up, the inevitable next time I do?

        Question Y:

        With a distibution installing is (almost) as easy as installing a CPAN module. Try to install your code on another maschine and make it runable!

        Question Z:

        Have you thought about (experience) using a Version Control System like git?

        With a Version Control System you can check when a file was added or editet.

        "distributions" are the standard way to share modules, to distribute them, and they're trivial (almost zero effort) to make, so call

        you can always run module-starter again in a different directory or with a different name or ...

Re: using File::Find to find recently-installed modules
by Marshall (Canon) on Jun 24, 2016 at 13:51 UTC
    stevieb is correct, creation time is not possible on Unix. It is possible on Windows, but the standard Perl built-in functions are not sufficient. I wrote this 6 years ago, might be helpful: Re^2: How to get the File creation date

      I plead guilty to whatever XY drift there is in the unrolling specification here, but a proper sailor in high seas will not abandon his complete mystification without reporting it as well as he can, for others with better perspective perchance to hear. It would seem files in the local::lib are not possessed of a,c, or mtime, whilst my crummy modules have all 3. My current best script follows with abridged output.

      use strict; use warnings; use 5.014; use File::Find; my @directories_to_search = ( '.', 'C:\Users\Fred\Desktop' ); my @files; find( \&wanted, @directories_to_search ); my @time = localtime; say "local time is @time"; sub wanted { if ( $_ =~ m/.pm$/ ) { my $name = $File::Find::name; my $success = max_acm($name); say "max_acm is $success"; push( @files, $name ); } } sub max_acm { use strict; use 5.014; use warnings; my $path = shift; say "$path is $path"; my @array; push @array, 42; my $atime = ( stat $path )[8]; if ( defined $atime ) { say "atime is ok"; push @array, $atime; } my $ctime = ( stat $path )[10]; if ( defined $ctime ) { say "ctime is ok"; push @array, $ctime; } my $mtime = ( stat $path )[9]; if ( defined $mtime ) { say "mtime is ok"; push @array, $mtime; } my $max = ( sort { $b <=> $a } @array )[0]; return $max; }
      max_acm is 42 ./perl5/lib/perl5/Prompt/Timeout.pm is ./perl5/lib/perl5/Prompt/Timeou +t.pm max_acm is 42 ./perl5/lib/perl5/WWW/Mechanize/GZip.pm is ./perl5/lib/perl5/WWW/Mecha +nize/GZip.pm max_acm is 42 C:\Users\Fred\Desktop/alpaca/template_stuff/config1.pm is C:\Users\Fre +d\Desktop/alpaca/template_stuff/config1.pm atime is ok ctime is ok mtime is ok max_acm is 1465162519 C:\Users\Fred\Desktop/alpaca/template_stuff/html1.pm is C:\Users\Fred\ +Desktop/alpaca/template_stuff/html1.pm atime is ok ctime is ok mtime is ok max_acm is 1465162519

      The times I'm looking for *in this context* are bounded below by when they become files in this locale. As further indication of XY shift, I would stipulate that it is sufficient to take the max of them, just in order to make useful time comparisons that will work for gilligan's island. I could just as well write a min function, compare it to the max, and have an interesting statistic about age, but first I'm trying to get squared away with the material in the exercises. I'm still *finding* modules, so I have to wonder how perl is interpreting the underlying windows platform. That neither a,c nor m time for the unix installed modules exists knocks my socks off and, along with the sea forward and backslashes, makes me believe that my logic is faulty.

      Again, thanks for your comment.

        That neither a,c nor m time for the unix installed modules exists knocks my socks off and, along with the sea forward and backslashes, makes me believe that my logic is faulty.

        The issue is that you have a relative path, the '.' File::Find does a cd as it navigates downwards. By the time you do the file test, you are not where you think you are and the file test fails. Since you are actually "in the directory", you can use the simple name of the file, eg. just "Timeout.pm". File::Basename can get that from $File::Find::name. The branch which started with an absolute path name works fine because it doesn't matter what directory that you are in when you do the stat.

        update: It is not necessary to use "\" on Windows. The "/" will work just fine. That is also true from the command line. The "\" is a hold over from DOS days and causes obvious problems due to its special meaning in Perl.

        Also worthy of note are side effects of this changing working directory business. If you code something that could "blow up" in Find, you will be left in some random part of the directory tree.

        Update:
        Here is some code to demo what I've said. I started in the ".." directory and used basename($File::Find::name) to do a simple file test on the basename.

        #!/usr/bin/perl use warnings; use strict; use File::Find; use File::Basename; find (\&for_every_name,'..',); sub for_every_name { my $basename = basename($File::Find::name); return unless $basename =~ /\.pl$/; print "$File::Find::name\n"; my $access_age = -A $basename; print " $basename, acccess age in days: $access_age\n"; } __END__ Abridged output: ../SSPH_Results/cmpN1MMarrlresults.pl cmpN1MMarrlresults.pl, acccess age in days: 40.9642361111111 ../SSPH_Results/convert2oldCSV.pl convert2oldCSV.pl, acccess age in days: 17.5422685185185 .....deleted..... ../testing/FileFinder.pl FileFinder.pl, acccess age in days: 1.15740740740741e-005 Note: *** "FileFinder.pl" is the name of this file, hence the Note: *** very short last access time! ../testing/fileFindexample.pl fileFindexample.pl, acccess age in days: 0.110034722222222

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1166461]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-18 21:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found