NAME
Scriptalicious - Delicious scripting goodies
SYNOPSIS
use Scriptalicious
-progname => "pu";
our $VERSION = "1.00";
my $url = ".";
getopt getconf("u|url" => \$url);
run("echo", "doing something with $url");
my $output = capture("svn", "info", $url);
__END__
=head1 NAME
pu - an uncarved block of wood
=head1 SYNOPSIS
pu [options] arguments
=head1 DESCRIPTION
This script's function is to be a blank example that many
great and simple scripts may be built upon.
Remember, you cannot carve rotten wood.
=head1 COMMAND LINE OPTIONS
=over
=item B<-h, --help>
Display a program usage screen and exit.
=item B<-V, --version>
Display program version and exit.
=item B<-v, --verbose>
Verbose command execution, displaying things like the
commands run, their output, etc.
=item B<-q, --quiet>
Suppress all normal program output; only display errors and
warnings.
=item B<-d, --debug>
Display output to help someone debug this script, not the
process going on.
=back
DESCRIPTION
This module helps you write scripts, quickly. Just include the above as a template. Unfortunately, it is not possible to have a `use' dependency automatically add structure to your POD yet, so you have to include the above manually. If you want your help message to be meaningful, that is.
To avoid all that unnecessary explicit importing of symbols, the following symbols and functions are exported into the caller's namespace:
$VERBOSE
-
Set to 0 by default, and 1 if
-v
or--verbose
was found during the call togetopt()
. Extra-v
's or--debug
will push this variable higher. If-q
or <--quiet> is specified, this will be less than one. $PROGNAME
-
It is recommended that you only ever read this variable, and pass it in via the import. This is not automatically extracted from the POD for performance reasons.
- getopt(@getopt_args)
-
Fetch arguments via
Getopt::Long::GetOptions
. Thebundling
option is enabled by default - which differs from the standard configuration of Getopt::Long. To alter the configuration, simply callGetopt::Long::config
. See Getopt::Long for more information. - getconf(@getopt_args)
-
Fetches configuration, takes arguments in the same form as getopt()..
The configuration file is expected to be in ~/.PROGNAMErc, /etc/perl/PROGNAME.conf, or /etc/PROGNAME.conf. Only the first found file is read, and unknown options are ignored for the time being.
The file is expected to be in YAML format, with the top entity being a hash, and the keys of the hash being the same as specifying options on the command line. Using YAML as a format allows some simplificiations to getopt-style processing -
=s%
and=s@
style options are expected to be in a real hash or list format in the config file, and boolean options must be set totrue
orfalse
(or some common equivalents).Returns the configuration file as Load()'ed by YAML in scalar context, or the argument list it was passed in list context.
For example, this script should work As You'd Expect(tm):
getopt getconf ( "something|s" => \$foo, "invertable|I!" => \$invertable, "integer|i=i" => \$bar, "string|s=s" => \$cheese, "list|l=s@" => \@list, "hash|H=s%" => \%hash, );
Examples of valid command lines for such a script:
foo.pl --something foo.pl --invertable foo.pl --no-invertable <=== FORM DIFFERS IN CONFIG FILE foo.pl --integer=7 foo.pl --string=anything foo.pl --list one --list two --list three foo.pl --hash foo=bar --hash baz=cheese
Equivalent config files:
something: 1 invertable: on invertable: off integer: 7 string: anything list: - one - two - three list: [ one, two, three ] hash: foo: bar baz: cheese
Note that more complex and possibly arcane usages of Getopt::Long features may not work with getconf (patches welcome).
- getconf_f($filename, @getopt_args)
-
As getconf(), but specify a filename.
- say "something"
-
Prints a message to standard output, unless quiet mode (
-q
or--quiet
) was specified. For normal program messages. - mutter "progress"
-
Prints a message to standard output, if verbose mode (
-v
) or debug mode (-d
) is enabled (ie, if$VERBOSE > 0
). For messages designed to help a user of the script to see more information about what is going on. - whisper "detail"
-
Prints a message to standard output, if debug mode (
-d
) is enabled or multiple verbose options were passed (ie, if$VERBOSE > 1
). For messages designed to help a person debugging the script to see more information about what is going on internally to the script. - abort "won't go to sea in a storm"
-
Prints a short program usage message (extracted from the POD synopsis) and exits with an error code.
- moan "weather is miserable"
-
Prints a warning to standard error. It is preceded with the text
warning:
. The program does not exit. - barf "hit an iceberg"
-
Prints a warning to standard error. It is preceded with the text
warning:
. The program does not exit. - run("command", "arg1", "arg2")
-
Runs a command or closure, barf's with a relevant error message if there is a problem. Program output is suppressed unless running in verbose mode.
run()
and the three alternatives listed below may perform arbitrary filehandle redirection before executing the command. This can be a very convenient way to do shell-like filehandle plumbing.For example;
run( -in => sub { print "Hello, world!\n" }, -out => "/tmp/outfile", -out2 => "/dev/null", @command );
This will connect the child process' standard input (
-in
) to a closure that is printing "Hello, world!\n
". The output from the closure will appear on standard input of the run command. Note that the closure is run in a sub-process and so will not be able to set variables in the calling program.It will also connect the program's standard output (
-out
) to/tmp/outfile
, and its standard error (filehandle 2) to/dev/null
(the traditional way of junking error output).If you wanted to connect two filehandles to the same place, you could pass in
GLOB
references instead;run( -out => \*MYOUT, -out2 => \*MYOUT, @command );
Any filehandle can be opened in any mode;
-in
merely defaults to meaning-in0
, and-out
defaults to meaning-out1
. There is no-err
; use-out2
.-rw
exists (defaulting to-rw0
), but is probably of limited use.Here is an example of using
prompt_passwd()
to hijackgpg
's password grabbing;my $password = prompt_passwd("Encryption password: "); my $encrypted = run( -in4 => sub { print "$password\n" }, "gpg", "--passphrase-fd", "4", "-c", $file )
- run_err("command", "arg2", "arg1")
-
Same as run, but returns the error code rather than assuming that the command will successfully complete. Again, output it suppressed.
- capture("command", "1gra", "2gra")
-
runs a command, capturing its output, barfs if there is a problem. Returns the output of the command as a list or a scalar.
- capture_err("command", "foo")
-
Works as capture, but the first returned item is the error code of the command ($?) rather than the first line of its output. Also, it only ever returns the output as a list.
Usage:
my ($rc, @output) = capture_err("somecommand", @args);
- start_timer()
- show_delta()
- show_elapsed()
-
These three little functions are for printing run times in your scripts. Times are displayed for running external programs with verbose mode normally, but this will let you display running times for your main program easily.
- sci_unit($num, [$unit, $precision])
-
Returns a number, scaled using normal scientific prefixes (from atto to exa). Optionally specify a precision which is passed to sprintf() (see "sprintf" in perldoc). The default is three significant figures.
The scripts assumes an ISO-8559-1 encoding on output, and so will print a MU character (\265) to mean micro.
- prompt_regex($prompt, sub { /(.*)/ && $1 })
-
Prompts for something, using the prompt "
$prompt
", feeding the sub with the entered value (sans trailing linefeed), to use a default, the passed sub should simply return it with empty input. - prompt_passwd([$prompt])
-
Same as
prompt_regex
, but turns off echo.$prompt
defaults to "Password:
" for this function. - prompt_string([$prompt])
-
Prompt for a string.
- prompt_int([$prompt])
-
get an integer
- prompt_for([ [$type =] $what])>
-
Prompts for a value for
$what
. This constructs a prompt saying, eg "Enter value for $what
". Calls the equivalentprompt_foo()
method. - prompt_yn([$prompt])
-
prompts for yes or no, presuming neither
- prompt_Yn([$prompt])
- prompt_yN([$prompt])
-
prompts for yes or no, presuming yes and no, respectively.
- foo()
-
If you've got a short little Perl function that implements something useful for people writing Shell scripts in Perl, then please feel free to contribute it. And if it really is scriptalicious, you can bet your momma on it getting into this module!
SEE ALSO
Simon Cozen's Getopt::Auto module does a very similar thing to this module, in a quite different way. However, it is missing say
, run
, etc. So you'll need to use some other module for those. But it does have some other features you might like and is probably engineered better.
There's a template script at "Documentation and help texts" in Getopt::Long that contains a script template that demonstrates what is necessary to get the basic man page / usage things working with the traditional Getopt::Long and Pod::Usage combination.
Getopt::Plus is a swiss army chainsaw of Getopt::* style modules, contrasting to this module's approach of elegant simplicity (quiet in the cheap seats!).
If you have solved this problem in a new and interesting way, or even rehashed it in an old, boring and inelegant way and want your module to be listed here, please contact the
AUTHOR
Sam Vilain, samv@cpan.org