Table of Contents
- Find the files location of a perl module
- Check if perl module is part of the core modules with Module::CoreList
- Working with perl lib directories and modules
- Reading file content
- Dynamic Function List Execution With GetOpts And Dispatcher
- Generating Usage/Man like help with Pod::Usage
- Using DateTime To Work With Dates
- Changine the umask of your script
- Changing PATH environment variable
- Adding random sleep / wait
- Check if script is running under screen session
- Escaping shell commands
- Storing and Loading object with Storable
- Simple and safe logging to a file for multiple concurrent processes using a lock
- Resources
The main idea of posting this post is for my own comfort (so I can find these things when I need them).
The code examples may not be suitable for direct insertion inside your script.
Find the files location of a perl module
perldoc -l Some::Module
Check if perl module is part of the core modules with Module::CoreList
There is a very handy module called “Module::CoreList” which resides inside perl core from version v5.8.9.
The module comes with pre-installed binary as well called “corelist”, which is handy for use:
# Search for a given module gryzli@localhost ]$ corelist List::Util Data for 2018-11-29 List::Util was first released with perl v5.7.3 # Search for all modules matching a regex gryzli@localhost [~/temp/perl_book]$ corelist /List/ Data for 2018-11-29 I18N::LangTags::List was first released with perl v5.7.3 Data for 2018-11-29 List::Util was first released with perl v5.7.3 Data for 2018-11-29 List::Util::PP was first released with perl v5.10.1 and removed from v5.17.1 ........ ....... .....
You could also use it inside perl script.
The following example will list you all core modules for a given perl version (ex: 5.10.0) .
#!/usr/bin/perl use strict; use warnings; use Module::CoreList; my $max_size = max map { length } keys %{$Module::CoreList::version{5.010000}}; foreach ( sort keys %{$Module::CoreList::version{5.010000}} ) { printf "Module: [%*s], First release:%s \n",- $max_size, $_,Module::CoreList->first_release($_); }
Working with perl lib directories and modules
Loading modules during runtime (not compile time)
If you are using “use XXX;” this loads the module during script compile time.
You are also able to load a module during the run time, by using “require“.
Manually installing module from CPAN
If you can’t install a package from CPAN with cpan or cpnam for some reason, you can compile it manually. The process is simple:
# Download the module, ex: Perl::Critic wget https://cpan.metacpan.org/authors/id/P/PE/PETDANCE/Perl-Critic-1.132.tar.gz # Untar the module # Compile it # IF MAKEFILE.PL % perl Makefile.PL INSTALL_BASE=/home/gryzli/perl5 make make test make install # IF Build.PL % perl Build.PL --install_base /home/gryzli/perl5 perl Build perl Build test perl Build install
The example above shows 2 different ways of compiling a module, depending on whether it has Makefile.PL or Build.PL.
Also there is additional argument “–install_base and INSTALL_BASE env” , which are telling make to install the module locally in my /home/gryzli/perl5 directory.
Adding additional lib directories to perl
Sometimes you may need to load perl module from a custom directory, not mentioned in your default perl @INC.
There are several ways to accomplish this, here are some examples:
Inside your perl script
# Modifications of @INC should be made inside BEGIN {}, because USE are run during compilation time BEGIN { unshift @INC, '/path/to/MyModule/some'}; use MyModule::Some; # Better is to use the 'use lib' pragma use lib '/path/to/MyModule/some'; use MyModule::Some;
Outside your perl script
# Modify the PERL5LIB environment variable, prior script execution # this could be made persistent in .bashrc/.bash_profile export PERL5LIB="$PERL5LIB:/path/to/my/module" perl some_script.pl # Adding custom libdir with -I during the script invocation perl -I /path/to/my/module some_script.pl
Reading file content
Some interesting method with do {}
my $file_contents = do { local $/; local @ARGV = ( $filename ); <> };
Dynamic Function List Execution With GetOpts And Dispatcher
Sometime you want to associate each new argument to your perl script, with separate function. If you write a lot of functions during the development, adding each function as an argument option (inside GetOptions) and also defining separate If() statement for checking it, could be boring.
In this case you can try executing the function dynamically, by using something like this:
#!/usr/bin/perl use strict; use warnings; my %opt; my %dispatch = ( your_new_argument => \&your_new_function, ); GetOptions (\%opt, keys %dispatch, ) ; # Check what has been supplied as argument and execute it foreach my $action (keys %dispatch){ $dispatch{$action}->() if defined ($opt{$action}); } sub your_new_function { print "Hello from your_new_function() \n"; }
Generating Usage/Man like help with Pod::Usage
If you are tired of writing usage() or help() functions for showing usage notes about your program, you may wish to consider Pod::Usage.
By using it, you will have consistent formatting through your help messages, and also will save some code.
Here it is a simple example:
use Pod::Usage qw(pod2usage); use Getopt::Long qw (GetOptions); # Parse the options my %opt; GetOptions (\%opt, "h|help", "man" ); # Print Usage if (defined $opt{h} or defined $opt{help}){ pod2usage(0); } if (defined $opt{man} ){ pod2usage(-verbose => 2); } # ..... # ..... # some code # .... __END__ =head1 NAME sample_script.pl =head1 SYNOPSIS sample_script.pl [options] =head1 OPTIONS =over 4 =item B<--help> Print a brief help message and exits. =item B<--man> Print extensive help page in Man Style =back =head1 DESCRIPTION Example script =head1 AUTHOR Written by Gryzli The Bugbear =head1 COPYRIGHT Copyright 2019, Gryzli.Info, all rights reserved. =cut
Showing the short version of the help
gryzli@localhost [~/temp]$ perl sample_script.pl --help Usage: sample_script.pl [options] Options: --help Print a brief help message and exits. --man Print extensive help page in Man Style
By running it with “–man” you could go to a man-like page , which will visualize all of the information in your POD.
Using DateTime To Work With Dates
use DateTime; # Print hh:mm:ss time print DateTime->now->hms # Print YY-MM-DD print DateTime->now->ymd ## OO Notation # Get current date my $date = DateTime->now() # Print current time in EPOCH (unix timestam) say $date->epoch();
Changine the umask of your script
Some time you may need to change the default umask in order to affect newly created files by your perl script. This could be easily done by adding the following to your script:
# Changing umask to 077 umask 077;
More about how umask works under Linux, could be read here:
https://wiki.archlinux.org/index.php/umask
Changing PATH environment variable
Sometimes you may need to execute binaries from path which is not currently inside your environment variable.
Also if your script is running as a CRON job, most probably your PATH would be much limited.
Adding new directories to PATH inside perl script is as easy as:
$ENV{PATH}="/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin:$ENV{PATH}";
It is good to append your current PATH to the end of the newly modified PATH string.
Adding random sleep / wait
# This will choose random number between 0 - 100 and wait these seconds sleep(int(rand(100)));
If you need to add sleep for a period less than a second , it would be good idea to use Time::HiRes perl module.
use Time::HiRes; # Sleep for microseconds usleep ($microseconds); # Sleep for nanoseconds nanosleep ($nanoseconds);
Check if script is running under screen session
Sometimes we write scripts that are intended to be run inside screen sessions for the sake of safety.
You could add check inside your script to make sure it is run inside screen session:
# Exit if we are not running inside screen session if (not defined $ENV{STY}){ print "ERROR: You are NOT in SCREEN session, please make sure you execute the script inside screen\n"; exit 1; }
Escaping shell commands
If you need to escape certain shell commands, you could use String::ShellQuote .
use String::ShellQuote ; my $quoted_command = shell_quote "some shell command" ;
Storing and Loading object with Storable
If you need to store your object and later re-load it with all of it’s data , you could use “Storable” module.
You could actually store your object and reload it in another script run and you will be able to access it’s functions and variables.
use Storable; # Storing the object store $my_object_reference , "file_to_store"; # Loading back the object my $object_ref = retrieve("file_to_store");
Simple and safe logging to a file for multiple concurrent processes using a lock
Let say you want to log events to a log and you have multiple scripts running in the same time and trying to save events to the same log file.
There is a pretty big chance the different processes to overlap lines in the log.
One of the ways you can achieve this is by Log::Log4perl::Appender::Synchronized .
If you want to make it less complicated, you could use function like this:
sub logger { my ($msg) = @_; my $logfile="/path/to/some/log.log" open my $fh, ">>", $logfile; flock $fh, LOCK_EX; print {$fh} $msg."\n"; close $fh; } # Log something &logger ("Some message here");