Building a Versatile Shell Script Template with Logging and Command Handling
Building a Versatile Shell Script Template with Logging and Command Handling
Creating reusable shell scripts can save a lot of time, especially when they’re structured to handle different commands, support logging, and track version history. Here i have provided a reference for a template structure for bash scripting. Hopefully I will continue to use this myself.
Step 1: Setting Up the Script Structure
We start by creating a basic structure for the script, including:
- Version information: to track the version number and author.
- Usage and description: to provide instructions on how to use the script.
- Changelog: a section for documenting changes across different versions.
Below is the initial setup for the template script. Copy this into a file called script_template.sh
.
#!/bin/bash
# script_template.sh - A template for command-line scripts with options and logging
# Version: 1.0
# Author: [Your Name]
# Description: A template script to demonstrate structured command-line argument parsing, logging, and modular command processing.
# Usage: ./script_template.sh {command1|command2} [--log]
# Example: ./script_template.sh command1 --log
# Changelog:
# Version 1.0 - [YYYY-MM-DD]: Initial release with basic command handling and logging functionality.
# Version 1.1 - [YYYY-MM-DD]: Added validation for required command arguments and improved error handling.
# Version 1.2 - [YYYY-MM-DD]: Enhanced logging function to support console-only and file logging.
# Version 1.3 - [YYYY-MM-DD]: Minor improvements, added documentation, and refactored functions for modularity.
# Version information
SCRIPT_VERSION="1.0"
# Default log file path
LOG_FILE="script_template.log"
LOG_TO_FILE=false
COMMAND=""
In this setup:
- Usage and example sections provide users with guidance on using the script.
- Changelog records updates for each version, with a description of changes.
Step 2: Parsing Command-Line Arguments
Our script template can take commands (e.g., command1
or command2
) and an optional --log
flag. This flag will enable logging to a file, while commands will determine the actions the script performs.
Here’s the code for parsing arguments:
# Parse command-line arguments
for arg in "$@"; do
case $arg in
--log)
LOG_TO_FILE=true
shift # Remove --log from processing
;;
command1|command2)
COMMAND=$arg
shift # Remove command from processing
;;
*)
echo "Invalid option: $arg"
echo "Usage: $0 {command1|command2} [--log]"
exit 1
;;
esac
done
# Validate that a command was provided
if [ -z "$COMMAND" ]; then
echo "Missing command. Usage: $0 {command1|command2} [--log]"
exit 1
fi
- Argument parsing: The script checks each argument. If
--log
is present, it setsLOG_TO_FILE=true
to enable logging. If a valid command (command1
orcommand2
) is found, it sets that command for execution. - Validation: If no command is provided, the script displays usage instructions and exits.
Step 3: Setting Up the Logging Function
This logging function outputs messages to the console and, optionally, to a log file. It uses LOG_TO_FILE
to determine if log entries should be saved to a file.
# Log function to output to console and optionally to a log file
log() {
if $LOG_TO_FILE; then
echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
else
echo "$(date +'%Y-%m-%d %H:%M:%S') - $1"
fi
}
# Log the start of the script and version
log "Starting script_template.sh - Version $SCRIPT_VERSION"
- Log timestamp: Each log entry includes a timestamp for easier tracking.
- Conditional logging: If
--log
is specified, logs are saved toscript_template.log
; otherwise, they display only in the console.
Step 4: Defining Commands
We’ll define placeholder functions for each command, allowing easy customization. Each function logs its actions for better transparency.
# Command function for 'command1'
execute_command1() {
log "Executing command1..."
# Add code for command1 here
log "Completed command1."
}
# Command function for 'command2'
execute_command2() {
log "Executing command2..."
# Add code for command2 here
log "Completed command2."
}
execute_command1
andexecute_command2
: These functions represent different actions the script can perform. For example, if this were a deployment script, one command could start the server, and the other could stop it.- Customizable functions: These placeholders allow you to add any code you need for each command, keeping the script organized and modular.
Step 5: Running the Commands
With all pieces in place, we add a case statement to call the appropriate function based on the command specified.
# Execute the specified command
case $COMMAND in
command1)
execute_command1
;;
command2)
execute_command2
;;
esac
# Log the end of the script execution
log "Completed script_template.sh - Version $SCRIPT_VERSION"
Step 6: Testing the Template
To test the script:
-
Enable Command Logging: Run with the
--log
option to write logs to a file../script_template.sh command1 --log
-
Run Without Logging: Run without
--log
to print output to the console only../script_template.sh command2
-
Invalid Commands: Try running the script with an unsupported command to test validation.
./script_template.sh invalid_command
Script: Full Script
#!/bin/bash
# script_template.sh - A template for command-line scripts with options and logging
# Version: 1.0
# Author: [Your Name]
# Description: A template script to demonstrate structured command-line argument parsing, logging, and modular command processing.
# Usage: ./script_template.sh {command1|command2} [--log]
# Example: ./script_template.sh command1 --log
# Changelog:
# Version 1.0 - [YYYY-MM-DD]: Initial release with basic command handling and logging functionality.
# Version 1.1 - [YYYY-MM-DD]: Added validation for required command arguments and improved error handling.
# Version 1.2 - [YYYY-MM-DD]: Enhanced logging function to support console-only and file logging.
# Version 1.3 - [YYYY-MM-DD]: Minor improvements, added documentation, and refactored functions for modularity.
# Version information
SCRIPT_VERSION="1.0"
# Default log file path
LOG_FILE="script_template.log"
LOG_TO_FILE=false
COMMAND=""
# Parse command-line arguments
for arg in "$@"; do
case $arg in
--log)
LOG_TO_FILE=true
shift # Remove --log from processing
;;
command1|command2)
COMMAND=$arg
shift # Remove command from processing
;;
*)
echo "Invalid option: $arg"
echo "Usage: $0 {command1|command2} [--log]"
exit 1
;;
esac
done
# Validate that a command was provided
if [ -z "$COMMAND" ]; then
echo "Missing command. Usage: $0 {command1|command2} [--log]"
exit 1
fi
# Log function to output to console and optionally to a log file
log() {
if $LOG_TO_FILE; then
echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
else
echo "$(date +'%Y-%m-%d %H:%M:%S') - $1"
fi
}
# Log the start of the script and version
log "Starting script_template.sh - Version $SCRIPT_VERSION"
# Command function for 'command1'
execute_command1() {
log "Executing command1..."
# Add code for command1 here
log "Completed command1."
}
# Command function for 'command2'
execute_command2() {
log "Executing command2..."
# Add code for command2 here
log "Completed command2."
}
# Execute the specified command
case $COMMAND in
command1)
execute_command1
;;
command2)
execute_command2
;;
esac
# Log the end of the script execution
log "Completed script_template.sh - Version $SCRIPT_VERSION"
Conclusion
This versatile script template provides a powerful foundation for creating structured, modular shell scripts. By including logging, command validation, and a changelog.