fluidmind
Star God: Fu Star God: Lu Star God: Shou

Command Line Script Setup

A code snippet to make CLI scripts more managable.

Copyright © 2013 by Daniel G. Delaney, Fluid Mind Software

The Command Line Script Setup is an easy way to add test mode, silent mode, and debug mode to your CLI scripts. With the code snippet in place at the top of your Perl, Bash, or PHP CLI scripts, a prompt will appear when you run your script that asks you if you actually want to run the script for real:

Usage: -noprompt, -silent, -test, -debug (self-explanatory parameters)
This script runs in TEST mode by default.
Do you want to run it for real [y/N]? 

If you just hit the ENTER key, it will default to being in test mode. To run the script for real, you either have to type a "Y" or run the script with the "-noprompt" parameter.

Parameters:

-noprompt
Run script for real, without prompting.
-test
Run script in test mode, without prompting.
-silent
Run script without any output to STDOUT. In silent mode, only output sent to STDERR will be seen.
-debug
Execute any code specified for debugging.

In order for the -silent, -test, and -debug parameters to work, you'll need to add a few conditionals throughout your scripts:

To run your script from a cron job, just add the -noprompt parameter to the command and either pipe the output to a log file or add the -silent parameter to keep cron from sending you an email message every time it runs the script. And since error messages will be output, cron will send you an email only when there was a problem.

Perl Version

Just copy and past this to the top of your script:

# Perl Command Line Script Setup
# @link    http://fluidmind.org/software/cli-setup/
# @author  Daniel G. Delaney
# @version 3.3
# See website for documentation.
use constant { false => 0, true => 1 };
my %args = map {$_=>1} @ARGV;
$silent = exists($args{'-silent'}) ? true : false;
$testMode = exists($args{'-test'}) ? true : false;
$debug = exists($args{'-debug'}) ? true : false;
if (!$testMode && !exists($args{'-noprompt'})) {
    print STDERR "\nUsage: -noprompt, -silent, -test, -debug (self-explanatory)\n" .
        "This script runs in TEST mode by default.\n" .
        "Do you want to run it for real [y/N]? ";
    $testMode = (substr(lc(<STDIN>), 0, 1) eq 'y' ? false : true);
}
@ARGV = grep(!/^(?:-silent|-test|-debug|-noprompt)$/, @ARGV);
sub printNotice { print $_[0] if (!$silent); }
sub printError { print STDERR $_[0]; }
sub printDebug { print STDERR $_[0] if ($debug); }
if ($testMode && !$silent) { print "\n*** RUNNING IN TEST MODE ***\n\n"; }
# End of Perl Command Line Script Setup

Example:

printNotice("Deleting user ID $userId.\n");
$sql = 'DELETE FROM users WHERE user_id = ' . $userId;
if (!$testMode) {
    $dbh->do($sql);
    if ($sth->err) {
        printError('Error: There was a problem with the database.');
        printDebug('Debug: ' . $dbh->errstr);
    }
} else {
    printDebug("Would have executed: $sql\n");
}

Bash Version

Just copy and past this to the top of your script:

# Bash Command Line Script Setup
# @link    http://fluidmind.org/software/cli-setup/
# @author  Daniel G. Delaney
# @version 3.3
# See website for documentation.
silent=false; testMode=false; debug=false; noprompt=false;
args=()
for arg in "$@"; do
    if   [ "$arg" = "-test" ]; then testMode=true;
    elif [ "$arg" = "-silent" ]; then silent=true;
    elif [ "$arg" = "-debug" ]; then debug=true;
    elif [ "$arg" = "-noprompt" ]; then noprompt=true;
    else args+=($arg)
    fi
done
set -- "${args[@]}"
if [ $testMode == false ] && [ $noprompt == false ]; then
    echo "Usage: -noprompt, -silent, -test, -debug (self-explanatory parameters)" 1>&2
    echo "This script runs in TEST mode by default." 1>&2
    echo -n "Do you want to run it for real [y/N]? " 1>&2
    read
    if [ "${REPLY:0:1}" = "y" ] || [ "${REPLY:0:1}" = "Y" ]; then testMode=false; else testMode=true; fi
fi
function printNotice { if [ $silent != true ]; then echo $1; fi }
function printDebug { if [ $debug == true ]; then echo $1 1>&2; fi }
function printError { echo $1 1>&2; }
if [ $testMode == true ] && [ $silent == false ]; then echo "*** RUNNING IN TEST MODE ***"; fi
# End of Bash Command Line Script Setup
    

Example:

printNotice "Some statement saying what this script will do."

if [ $testMode = false ]; then

    # Do something, and set $error to true if there was an error

    if [ $error = true ]; then
        printError "Report that there was a problem."
        printDebug "Output the technical error message."
    fi
else
    printNotice "Would have done something"
fi

PHP Version

Yes, PHP is great for CLI scripts. And the best part about using this setup code is that you can run the script from within a directory in your website, and it will be able to access the rest of the application as if it's being run through the web server. All you need to do is add a "/.." to the end of the line that defines $_SERVER['DOCUMENT_ROOT'] for each level up from DOCUMENT_ROOT this script is run from.

Just copy and past this to the top of your script:

/**
 * PHP Command Line Script Setup
 * @link    http://fluidmind.org/software/cli-setup/
 * @author  Daniel G. Delaney
 * @version 3.3
 */
if (PHP_SAPI == 'cli') {
    // If this is within a subdirectory of a website, add a "/.." to the end
    // of DOCUMENT_ROOT for each level up from the root this script is run from
    $_SERVER['DOCUMENT_ROOT'] = realpath(dirname($_SERVER['PHP_SELF']) . '');
    $_SERVER['SERVER_NAME'] = trim(shell_exec('hostname -f'));
    $_SERVER['SERVER_ADDR'] = gethostbyname($_SERVER['SERVER_NAME']);
    $silent = (in_array('-silent', $argv)) ? true : false;
    $testMode = (in_array('-test', $argv)) ? true : false;
    $debug = (in_array('-debug', $argv)) ? true : false;
    if (!$testMode and !(in_array('-noprompt', $argv) or in_array('-n', $argv))) {
        fputs(STDERR, "Usage: -noprompt, -silent, -test, -debug (self-explanatory parameters)\n" .
            "This script runs in TEST mode by default.\n" .
            "Do you want to run it for real [y/N]? ");
        $testMode = strtolower(substr(trim(fgets(STDIN)), 0, 1)) == 'y' ? false : true;
    }
    $argv = array_diff($argv, array('-test', '-silent', '-noprompt', '-debug'));
    define('SILENT', $silent); define('TEST_MODE', $testMode); define('DEBUG', $debug);
    function printNotice($message) { if (!SILENT) print $message; }
    function printDebug($message) { if (DEBUG) fputs(STDERR, $message); }
    function printError($message) { fputs(STDERR, $message); }
    if (TEST_MODE and !SILENT) { print "\n*** RUNNING IN TEST MODE ***\n\n"; }
}
/* End of PHP Command Line Script Setup */

Example:

printNotice("Deleting user ID $userId.");
$sql = 'DELETE FROM users WHERE user_id = ' . $userId;
if (!TEST_MODE) {
    try {
        $db->exec($sql);
    } catch (Exception $e) {
        printError('Error: There was a problem with the database.');
        printDebug('Debug: ' . $e->getMessage());
    }
} else {
    printNotice("Would have executed: $sql");
}