Name

Shell::Tools - Perl extension to reduce boilerplate in Perl shell scripts

Synopsis

use Shell::Tools;    # is the same as the following:

use warnings;
use strict;
use IO::File ();
use IO::Handle ();
use Carp qw/carp croak confess/;
use Pod::Usage 'pod2usage';
use Getopt::Std 1.04 'getopts';
sub main::HELP_MESSAGE { ... }            # calls pod2usage()
sub main::VERSION_MESSAGE { ... }         # see documentation below
$Getopt::Std::STANDARD_HELP_VERSION = 1;  # exit after --help or --version
use Cwd qw/getcwd cwd abs_path/;
use File::Spec::Functions qw/canonpath catdir catfile curdir rootdir updir
    no_upwards file_name_is_absolute splitdir abs2rel rel2abs/;
use File::Basename qw/fileparse basename dirname/;
use File::Temp qw/tempfile tempdir/;
use File::Copy qw/move copy/;
use File::Path 2.08 qw/make_path remove_tree/;
use File::Find 'find';
use Fcntl qw/LOCK_SH LOCK_EX LOCK_UN LOCK_NB SEEK_SET SEEK_CUR SEEK_END/;
use FindBin ();
use Data::Dumper 'Dumper';
use Scalar::Util 'looks_like_number';
use List::Util qw/first reduce/;

Description

This module exports a collection of functions from several core Perl modules which can often be very useful when writing Perl shell scripts.

See also Shell::Tools::Extra, which exports additional CPAN modules' functions and classes.

Warning

This module is intended to help write short, simple shell scripts. Because of its many exports it is not recommended for large applications, CGI scripts, object-oriented applications and the like.

Version

This document describes version 0.04 of Shell::Tools.

Exports

This module exports the following modules and functions.

Each module has an Exporter tag that is the same name as the module. This is useful if you want to exclude some modules' functions from being exported, for example use Shell::Tools qw/ !:File::Copy /;.

warnings and strict

These are enabled in the calling script. (No Exporter tag.)

IO::File and IO::Handle

These modules are loaded, nothing is exported. (No Exporter tag.)

Perl before v5.14 did not load these automatically. Loading these modules allows you to do things like:

open my $fh, ">", $file or die $!;
$fh->autoflush(1);
$fh->print("Hello");
# Note: calling binmode this way may not work on older Perls
$fh->binmode(":raw");

Carp

Carp's carp, croak and confess.

Getopt::Std and Pod::Usage

=head1 SYNOPSIS

 foo.pl [OPTIONS] FILENAME
 OPTIONS:
 -f       - foo
 -b BAR   - bar

=cut

getopts('fb:', \my %opts) or pod2usage;
pod2usage("must specify a filename") unless @ARGV==1;

This module provides the functions main::HELP_MESSAGE and main::VERSION_MESSAGE. HELP_MESSAGE simply calls pod2usage. VERSION_MESSAGE first checks for $main::VERSION_STRING and prints that if available, otherwise it will use $main::VERSION to construct a message, and if neither is available, it will use the "last modified" time of the script. Also, $Getopt::Std::STANDARD_HELP_VERSION is set, so the getopts call will exit the script if it sees --help or --version.

We require Getopt::Std 1.04 or greater for the support of the --help and --version switches.

Note that Pod::Usage before Version 1.36 only looked for a POD section titled SYNOPSIS; from 1.36 upwards it also looks for a section titled USAGE (note uppercase is always important).

Cwd

my $cwd = getcwd();  # POSIX getcwd(3)
my $cwd = cwd();
my $abs_path = abs_path($file);  # realpath(3)

File::Spec::Functions

my $path     = canonpath($path);
my $path     = catdir(@dirs);
my $path     = catfile(@dirs, $filename);
my @paths    = no_upwards(@paths);
my $is_abs   = file_name_is_absolute($path);
my @dirs     = splitdir($directories);
# note abs2rel() and rel2abs() use Cwd::cwd() if $base is omitted
my $rel_path = abs2rel($path, $base);
my $abs_path = rel2abs($path, $base);
my $curdir   = curdir();   # e.g. "."
my $rootdir  = rootdir();  # e.g. "/"
my $updir    = updir();    # e.g. ".."

# Hint - one way to list all entries in a directory:
my @files = do { opendir my $dh, "." or die $!; no_upwards readdir $dh };

See File::Spec for docs.

Note the additional Exporter tag File::Spec is provided as an alias for File::Spec::Functions.

File::Basename

my $filename = fileparse($path, @suffixes);  # suffixes optional
my ($filename, $dirs, $suffix) = fileparse($path, @suffixes);
$path = $dirs . $filename . $suffix;

The functions basename and dirname are also provided for compatibility, but File::Basename says that fileparse is preferred.

File::Temp

my $fh = tempfile();
my ($fh,$fn) = tempfile(UNLINK=>1);
my (undef,$fn) = tempfile(OPEN=>0);
my $tmpdir = tempdir(CLEANUP=>1);

File::Copy

copy("src","dst") or die "Copy failed: $!";
move("src","dst") or die "Move failed: $!";

File::Path

# will carp and croak
make_path('foo/bar/baz', '/quz/blah');
remove_tree('foo/bar/baz', '/quz/blah');

Note that we require File::Path 2.08 or greater because its interface has undergone several changes and its documentation strongly recommends using this version or newer.

File::Find

find({ no_chdir=>1, wanted=>sub {
    return if -d;
    ...;
} }, @DIRS);

Fcntl (selected)

SEEK_* (seek) and LOCK_* (flock)

FindBin

Nothing is exported; use these variables: $FindBin::Bin, $FindBin::Script, $FindBin::RealBin, and $FindBin::RealScript

Data::Dumper

print Dumper(\%ENV);

Scalar::Util (selected)

my $nr = "123.45";
print "$nr looks like a number" if looks_like_numer($nr);

List::Util (selected)

# first is more efficient than grep for boolean tests
my $found = first { /3/ } 10..20;
my $maxval = reduce { $a > $b ? $a : $b } 1..10;

See Also

  • Shell::Tools::Extra - extension of this module that also exports several functions from several CPAN modules

  • Env - imports environment variables as scalars or arrays

    use Env qw(HOME USER @PATH);
  • File::stat - by-name interface to Perl's built-in stat() functions

    my $st = stat($filename) or die $!;
    print "$filename is executable\n" if $st->mode & 0111;
    print "$filename has links\n" if $st->nlink > 1;

    Please see the "Bugs" section of File::stat - $_ and _ (currently) do not work with stat and lstat!

  • File::Slurp

    Since slurping a file can be as simple as the following, it's left up to the user to import this module if desired.

    my $slurp = do { open my $fh, '<', $filename or die $!; local $/; <$fh> };
  • Configuration file parsers: Config::General, Config::Perl (one of my modules), Config::IniFiles, Config::INI (simpler INI files), and Config::Tiny (even simpler INI files). For XML, JSON, and YAML, there are many modules available, some examples are: YAML::XS, XML::Simple, and JSON.

Author, Copyright, and License

Copyright (c) 2014 Hauke Daempfling (haukex@zero-g.net).

This library is free software; you can redistribute it and/or modify it under the same terms as Perl 5 itself.

For more information see the Perl Artistic License, which should have been distributed with your copy of Perl. Try the command "perldoc perlartistic" or see http://perldoc.perl.org/perlartistic.html.