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
--logis present, it setsLOG_TO_FILE=trueto enable logging. If a valid command (command1orcommand2) 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
--logis 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_command1andexecute_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
--logoption to write logs to a file../script_template.sh command1 --log -
Run Without Logging: Run without
--logto 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.