The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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.