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
-test
-silent
STDERR
will be seen.-debug
In order for the -silent
, -test
, and
-debug
parameters to work, you'll need to add a few
conditionals throughout your scripts:
printNotice()
function (or Write-Notice
in
PowerShell), which checks for silent mode to determine whether or not to
actually output the message.printError()
functino to
output to STDERR
.printDebug()
function, which will
output the message to STDERR
even when in silent modeTo 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.
Just copy and paste this to the top of your script:
# Perl CLI Script Setup # @link http://fluidmind.org/software/cli-setup/ (see for documantation) # @author Daniel G. Delaney # @version 3.3 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 CLI 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"); }
Just copy and paste this to the top of your script:
# Bash CLI Script Setup # @link http://fluidmind.org/software/cli-setup/ (see for documentation) # @author Daniel G. Delaney # @version 3.3 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 CLI 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
PowerShell already has Write-Error and Write-Debug functions. For the -Debug parameter to work, you must have a [CmdletBinding()] line toward to top of your script.
You'll have to have the -NoPrompt, -Test, and -Silent parameter lines in the Param() statement toward the top of your script, before the Begin{} segment.
Copy the CLI Setup snippet itself into the Begin{} segment of your script. If you aren't using Begin{} and Process{} segments, just put it close to the top of your script.
# Copy this to the top of your script (or make sure you have one like it) [CmdletBinding()] # Copy this to the top of your script, before the Begin{} segment, # or add these parameters to your current Param() statement Param ( [switch]$NoPrompt, [switch]$Test, [switch]$Silent ) # PowerShell CLI Setup # @link http://fluidmind.org/software/cli-setup/ (see for documentation) # @author Daniel G. Delaney # @version 1.2 if (!$Test -and !$NoPrompt) { Write-Host ("`nUsage: -NoPrompt, -Silent, -Test, -Debug (self-explanatory)`n" + "This script runs in TEST mode by default.") $forReal = Read-Host "Do you want to run it FOR REAL [y/N]?" $Test = ($forReal.Length -gt 0 -and $forReal.Substring(0,1).ToLower() -eq 'y') ? $false : $true } function Write-Notice($message) { if (!$Silent) { Write-Output $message; } } if ($Test) { $ErrorActionPreference = "Continue"; Write-Notice "`n*** RUNNING IN TEST MODE ***`n`n" } # End of PowerShell CLI Setup
Example:
Write-Notice("Deleting user ID $userId.") $sql = 'DELETE FROM users WHERE user_id = ' + $userId if (!$Test) { try { $SqlCmd.CommandText = $sql $rowsAffected = $SqlCmd.ExecuteNonQuery() } catch { Write-Error 'There was a problem with the database.' Write-Debug $error[0] } } else { Write-Notice "Would have executed: $sql"; }
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. I usually have a lib/bin directory in document_root, or you might just have a bin directory, for CLI scripts.
Just copy and paste this to the top of your script:
/** * PHP CLI Script Setup * @link http://fluidmind.org/software/cli-setup/ (see for documentation) * @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 CLI 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"); }