Seitenanfang

Perl -M-A-C tests

Perl supports various tests for file and directory states. Most are identical to their bash test siblings, but some additional are supported, like -M, -A and -C.

Perl_MAC_tests.pngPerl is great. I'm working with it for 16 years - but still discover something new from time to time. Today, I stumbled into the MAC tests while browsing the perlvar documentation page for something completly different. I wanted to quick check $^T before using it (yes, sometime I also look up basic default variables before using them and I was right to do so, because I mixed up $^S (which might have been start time, but isn't) with $^T which is the (unix)Timestamp recoded at the start of the script).

I suddenly noticed, that $^T was referring to three one-letter-tests I didn't know. But as long as perlfunc is available, help is not far away:

-M Script start time minus file modification time, in days.
-A Same for access time.
-C Same for inode change time (Unix, may differ for other platforms)

I did some (persistent) scripts lately which are checking for updated modules they're using, but I

a) didn't have the idea to simply check their modification time against $^T

and

b) didn't ever think that special Perl tests might exist for this usage case.

But Perl is TIMTOWTDI and now I know at least three of them to check if a - for example - Gearman worker process should restart itself to reload changed modules. The shortest might be:

exit if grep { -M $_ < 0 } values %INC;

(Which doesn't cover the script itself, but all loaded modules.)

Here is a commented version of the same line:

exit if        # Exit the currently running Perl script if the following condition matches...
grep { # Run the code between { and } for each item of the array given at the end
# returning those who are true
-M $_ # Compare the modification time of the filename in $_ to the start time of
# the current script and return the difference
< 0 # Return true if the -M comparison returned a value lower than zero
# (= file has been modified since script start)
}
values %INC; # Loop through the %INC hash and return all values = filenames of loaded
# modules

Any questions left?

 

2 Kommentare. Schreib was dazu

  1. reneeb

    Especially when %INC can become very big, you might better use "first" from List::Util. And you might be interested in Module::Refresh that is designed for such use cases mentioned in your blogpost.

    • Sebastian

      I thought about using List::Util, because I didn't want to introduce another dependeny, but you're right, it's better than grep.
      Refreshing modules is dangerous, I saw many problems in various projects. Restarting the process may avoid a lot of trouble - unless you restart every second.

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>