The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.


App::Basis - Simple way to create applications


version 1.2


    use 5.10.0 ;
    use strict ;
    use warnings ;
    use POSIX qw(strftime) ;
    use App::Basis

    sub ctrlc_func {
        # code to decide what to do when CTRL-C is pressed

    sub cleanup_func {
        # optionally clean up things when the script ends

    sub debug_func {
        my ($lvl, $debug) = @_;
        if(!$debug) {
            $debug = $lvl ;
            # set a default level
            $lvl = 'INFO' ;

        say STDERR strftime( '%Y-%m-%d %H:%M:%S', gmtime( time() ) ) . " [$lvl] " . get_program() . " " . $debug;

    # main
    my %opt = App::Basis::init_app(
    help_text   => 'Sample program description'
    , help_cmdline => 'extra stuff to print about command line use'
    , options   =>  {
        'file|f=s'  => {
            desc => 'local system location of xml data'
            , required => 1
        , 'url|u=s' => {
            desc => 'where to find xml data on the internet'
            , validate => sub { my $url = shift ; return $url =~ m{^(http|file|ftp)://} ; }
        , 'keep|k'  => {
            # no point in having this if there is no file option
            desc => 'keep the local file, do not rename it'
            , depends => 'file'
        , 'counter|c=i' => {
            desc => 'check a counter'
            , default   => 5
        , 'basic'   => 'basic argument, needs no hashref data'
    , ctrl_c   => \&ctrl_c_handler  # override built in ctrl-c handler
    , cleanup  => \&cleanup_func    # optional func to call to clean up
    , debug    => \&debug_func      # optional func to call with debugging data
    , 'verbose|v' => 'be verbose about things',
    , log_file => "~/log/fred.log"  # alternative place to store default log messages
    ) ;

    show_usage("need keep option") if( !$opt{keep}) ;

    msg_exit( "spurious reason to exit with error code 3", 3) ;


There are a number of ways to help script development and to encorage people to do the right thing. One of thses is to make it easy to get parameters from the command line. Obviously you can play with Getopt::Long and continuously write the same code and add in your own handlers for help etc, but then your co-workers and friends make not be so consistent, leading to scripts that have no help and take lots of cryptic parameters.

So I created this module to help with command line arguments and displaying help, then I added App::Basis::Config because everyone needs config files and does not want to constantly repeat themselves there either.

So how is better than other similar modules? I can't say that it is, but it meets my needs.

There is app help available, there is basic debug functionality, which you can extend using your own function, you can daemonise your script or run a shell command and get the output/stderr/return code.

If you choose to use App::Basis::Config then you will find easy methods to manage reading/saving YAML based config data.

There are (or will be) other App::Basis modules available to help you write scripts without you having to do complex things or write lots of code.

There is a helper script to create the boilerplate for an appbasis script, see appbasis



Public Functions


Set the name of the log file for the debug function

    set_log_file( "/tmp/lof_file_name") ;
    debug( "INFO", "adding to the debug log") ;

Write some debug data. If a debug function was passed to init_app that will be used, otherwise we will write to STDERR.

    debug( "WARN", "some message") ;
    debug( "ERROR", "Something went wrong") ;

Parameters string used as a 'level' of the error array of anything else, normally error description strings

If your script uses App::Basis make sure your modules do too, then any debug can go to your default debug handler, like log4perl, but simpler!


Tell App:Simple to use a different function for the debug calls. Generally you don't need this if you are using init_app, add the link there.

Parameters coderef pointing to the function you want to do the debugging


Turn on use of verbose or verbose_data functions, verbose outputs to STDERR its different to debug logging with generally will go to a file

    set_verbose( 1) ;
    verbose( "note that I performed some action") ;

Write to STDERR if verbose has been turned on its different to debug logging with generally will go to a file

    set_verbose( 1) ;
    verbose( "note that I performed some action") ;

Dump a data structure to STDERR if verbose has been turned on its different to debug logging with generally will go to a file

    set_verbose( 1) ;
    verbose_data( \%some_hash) ;

Parameters hash of these things

    help_text    - what to say when people do app --help
    help_cmdline - extra things to put after the sample args on a sample command line (optional)
    cleanup      - coderef of function to call when your script ends (optional)
    debug        - coderef of function to call to save/output debug data (optional, recommended)
    'verbose'    - use verbose mode (optional) will trigger set_verbose by default
    log_file     - alternate name of file to store debug to
    ctrlc_func   - coderef of function to call when user presses ctrl-C
    options      - hashref of program arguments
      simple way
      'fred'     => 'some description of fred'
      'fred|f'   => 'fred again, also allows -f as a variant'
      'fred|f=s' => 'fred needs to be a string'
      'fred|f=i' => 'fred needs to be an integer'

      complex way, more features, validation, dependancies etc
      'fred|f=s' => {
         desc      => 'description of argument',
         # check if fred is one of the allowed things
         validate  => sub { my $fred = shift ; $fred =~ m/bill|mary|jane|sam/i ;},
         # does this option need another option to exist
         depends   => 'otheroption'
      'fred|f=s' => {
         desc     => 'description of argument',
         default  => 'default value for fred'

Note will die if not passed a HASH of arguments


get the name of the running program just a helper function


return the command line options hash just a helper function


show how this program is used, outputs help, parameters etc, this is written to STDERR

Parameters msg - additional message to explain why help is displayed (optional) state - int value to exit the program with

Sample output help Syntax: app [options] other things

    About:  Boiler plate code for an App::Basis app

        -h, --help          Show help
        -i, --item          another item [DEFAULT: 123]
        -t, --test          test item [DEFAULT: testing 123]
        -v --verbose        Dump extra useful information

Exit this program writting a message to to STDERR

Parameters msg - message to explain what is going on state - int value to exit the program with


create a daemon process, detach from the controlling tty if called by root user, we can optionally specify a dir to chroot into to keep things safer

Parameters rootdir - dir to root the daemon into (optional, root user only)

Note: will die on errors

 execute_cmd(command => ['/my/command','--args'], timeout => 10);

Executes a command using IPC::Cmd::run_forked, less restrictive than run_cmd see IPC::Cmd for more options that

Input hashref

    command         - string to execute (arrayrefs aren't supported, for some reason)
    timeout         - timeout (in seconds) before command is killed
    stdout_handler  - see IPC::Cmd docs
    stderr_handler  - see IPC::Cmd docs
    child_stdin     - pass data to STDIN of forked processes
    discard_output  - don't return output in hash


    exit_code       - exit code
    timeout         - time taken to timeout or 0 if timeout not used
    stdout          - text written to STDOUT
    stderr          - text written to STDERR
    merged          - stdout and stderr merged into one stream
    err_msg         - description of any error that occurred.

Basic way to run a shell program and get its output, this is not interactive. For interactiviness see execute_cmd.

By default if you do not pass a full path to the command, then unless the command is in /bin, /usr/bin, /usr/local/bin then the command will not run.

my ($code, $out, $err) = run_cmd( 'ls') ; # ($code, $out, $err) = run_cmd( 'ls -R /tmp') ;

Parameters string to run in the shell timeout (optional) in seconds


Simple way to replace ~, ./ and ../ at the start of filenames

Parameters file name that needs fixing up


convert markdown text into something that can be output onto the terminal

saymd "# # Bringing MD Like Syntax To Bash Shell It should be something as ***easy*** and as ___natural___ as writing text.

> Keep It Simple > With quoted sections

Is the idea

  * behind
  * all this

~~~striking~~~ UX for `shell` users too. - - - #green(green text) bg#red(red background text) " ;


Kevin Mulholland <>


This software is copyright (c) 2017 by Kevin Mulholland.

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