diff --git a/README.md b/README.md index fceb73e..6c81025 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,12 @@ # ReachableCEOShellFramework -My shell scripting framework developed over the years \ No newline at end of file +## Introduction + +My shell scripting framework developed over 20 years of coding bash professionally. + +This is a collection of code/functions/templates/methodologies I've put together over 20 years of coding. + +* Error handling/tracing +* Help +* Robust CLI argument handling + diff --git a/README_template.md b/README_template.md new file mode 100644 index 0000000..273c4b0 --- /dev/null +++ b/README_template.md @@ -0,0 +1,12 @@ +# + + +## Introduction + +This is a project.It does stuff.. + +## Assumptions + +## Requirements + +## Dependencies diff --git a/includes/DebugMe.sh b/includes/DebugMe.sh new file mode 100644 index 0000000..d4414f1 --- /dev/null +++ b/includes/DebugMe.sh @@ -0,0 +1,33 @@ +function DebugMe() { + [[ $script_debug = 1 ]] && "$@" || : + +#to turn debugging on, set script_debug=1 +#to turn debugging off, set script_debug=0 + +# be sure to append || : or || true here or use return 0, since the return code +# of this function should always be 0 to not influence anything else with an unwanted +# "false" return code (for example the script's exit code if this function is used +# as the very last command in the script) + +#This function does nothing when script_debug is unset or empty, but it executes the +#given parameters as commands when script_debug is set. Use it like this: + +#debugme logger "Sorting the database" +#database_sort +#debugme logger "Finished sorting the database, exit code $?" + + +# * print commands to be executed to stderr as if they were read from input +# (script file or keyboard) +# * print everything before any ( substitution and expansion, …) is applied +set -v + +# * print everything as if it were executed, after substitution and expansion is applied +# * indicate the depth-level of the subshell (by default by prefixing a + (plus) sign to +# the displayed command) +# * indicate the recognized words after word splitting by marking them like 'x y' +# * in shell version 4.1, this debug output can be printed to a configurable file +#descriptor, rather than sdtout by setting the BASH_XTRACEFD variable. +set -x + +} diff --git a/includes/LocalHelp.sh b/includes/LocalHelp.sh new file mode 100644 index 0000000..de3918f --- /dev/null +++ b/includes/LocalHelp.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +function LocalHelp() +{ + echo "$0 is " + echo "$0 takes arguments: " + echo "1) " + echo "2) " + echo ":" + echo "" + echo "" + echo "" +} diff --git a/includes/LookupKv.sh b/includes/LookupKv.sh new file mode 100644 index 0000000..362a7d4 --- /dev/null +++ b/includes/LookupKv.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +function LookupKV() +{ + +#Arguments: +#$1 +#$2 unique record identifier + +#Returns: +#Variable/array containing all the values in the record + +} diff --git a/includes/PreflightCheck.sh b/includes/PreflightCheck.sh new file mode 100644 index 0000000..282a798 --- /dev/null +++ b/includes/PreflightCheck.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +function PreflightCheck() +{ + +#Common things I check for in the scripts I write. + +#export curr_host="$(hostname)" +#export curr_user="$USER" +#export host_check="$(echo $curr_host | grep -c )" +#export user_check="$(echo $curr_user | grep -c )" + +#if [ $host_check -ne 1 ]; then +# echo "Must run on ." +# error_out +#fi + +#if [ $user_check -ne 1 ]; then +# echo "Must run as ." +# error_out +#fi + +#if [ "$ARG_COUNT" -ne ]; then +# help +# error_out +#fi + +#Your additional stuff here... +echo "All checks passed...." + +} diff --git a/includes/bail_out.sh b/includes/bail_out.sh new file mode 100644 index 0000000..cae8d46 --- /dev/null +++ b/includes/bail_out.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +bail_out() +#Exit code +{ +echo "Exiting...." +exit 0 +} diff --git a/includes/error_out.sh b/includes/error_out.sh new file mode 100644 index 0000000..45764af --- /dev/null +++ b/includes/error_out.sh @@ -0,0 +1,23 @@ +#!/bin/bash + + +function error_out() +{ + echo "Bailing out. See above for reason...." + exit 1 +} + + +function handle_failure() { + local lineno=$1 + local fn=$2 + local exitstatus=$3 + local msg=$4 + local lineno_fns=${0% 0} + if [[ "$lineno_fns" != "-1" ]] ; then + lineno="${lineno} ${lineno_fns}" + fi + echo "${BASH_SOURCE[0]}: Function: ${fn} Line Number : [${lineno}] Failed with status ${exitstatus}: $msg" +} + +trap 'handle_failure "${BASH_LINENO[*]}" "$LINENO" "${FUNCNAME[*]:-script}" "$?" "$BASH_COMMAND"' ERR diff --git a/includes/strictMode.sh b/includes/strictMode.sh new file mode 100644 index 0000000..ba8159c --- /dev/null +++ b/includes/strictMode.sh @@ -0,0 +1,41 @@ +#!/bin/bash + + +function StrictMode() +{ + +# Standard strict mode and error handling boilderplate.. + +# This is a function I include and execute in every shell script that I write. +# It sets up a bunch of error handling odds and ends + +# Bits and pieces Sourced from (as best I recall): +# * https://news.ycombinator.com/item?id=24727495 +# * many other hacker news / slashdot etc posts over the years +# * https://www.tothenew.com/blog/foolproof-your-bash-script-some-best-practices/ +# * https://translucentcomputing.com/2020/05/unofficial-bash-strict-mode-errexit/ +# * http://redsymbol.net/articles/unofficial-bash-strict-mode/ +# * the school of hard knocks... (aka my code failures...) + +#Here's the beef (as the commercial says..) + +#use errexit (a.k.a. set -e) to make your script exit when a command fails. +#add || true to commands that you allow to fail. +set -o errexit + +# Use set -o nounset (a.k.a. set -u) to exit when your script tries to use undeclared +# variables. +set -o nounset + +#Use set -o pipefail in scripts to catch (for example) mysqldump fails +#in e.g. mysqldump |gzip. +#The exit status of the last command that threw a non-zero exit code is returned +set -o pipefail + +#Function tracing... +set -o functrace + + +export PS4='(${BASH_SOURCE}:${LINENO}): - [${SHLVL},${BASH_SUBSHELL},$?] $ ' + +} \ No newline at end of file diff --git a/project.sh b/project.sh new file mode 100644 index 0000000..21fb956 --- /dev/null +++ b/project.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +#Framework variables are read from hee +source vars/FrameworkVars + +#Boilerplate and support functions +FrameworkIncludeFiles="$(ls -1 --color=none includes/*)" + +IFS=$'\n\t' +for file in ${FrameworkIncludeFiles[@]}; do + . "$file" +done +unset IFS + + +if [[ ProjectIncludes = 1 ]]; then +ProjectIncludeFiles="$(ls -1 --color=none project-includes/*)" +IFS=$'\n\t' +for file in ${ProjectIncludeFiles[@]}; do + . "$file" +done +unset IFS +fi + + +##### +#Core framework functions... +##### + + +while [ ! -z "$1" ];do + case "$1" in + -h|--help) + LocalHelp + ;; + -k1|--key1) + shift + KEY1="$1" + echo "key 1 is $KEY1" + ;; + -k2|--key2) + shift + KEY2="$1" + echo "key 2 is $KEY2" + ;; + *) + echo "Displaying $0 help..." + LocalHelp + esac +shift +done + + +function main() +{ +StrictMode + +if [ PreflightCheck = 1 ]; then +PreflightCheck +fi + +#Your custom logic here.... +echo "Custom logic here..." +} + +main diff --git a/vars/FrameworkVars b/vars/FrameworkVars new file mode 100644 index 0000000..bb7505a --- /dev/null +++ b/vars/FrameworkVars @@ -0,0 +1,5 @@ +#Global Variables used by the framework + +export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' +export ProjectIncludes="0" +export PreflightCheck="0" diff --git a/vars/kv_map b/vars/kv_map new file mode 100644 index 0000000..510a7e0 --- /dev/null +++ b/vars/kv_map @@ -0,0 +1,19 @@ +#Place (primary/unique) key as very first argument on each record below + +#Value Fields are (in order), (reference KEY_(VARIABLE) names in the code): +#1)valuex (description) +#2)valuey (description) +#3)valuez (description) + +#An example: +#unique key of serverfqdn +#key of: subnet , value of: 10.10.10.0/24 +#key of: gateway, value of: 10.10.10.1 + +#serverfqdn,10.10.10.0/24,10.10.10.1 + +#Place your records below: + +#primary/uniquekey,#value +primarykey1,valuex,valuey,valuez +primarykey2,valuex,valuey,valuez