Squashed commit of the following:

commit 61bf734812cb62ba6e0ec224bc15f7928705a8a2
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Thu Oct 21 15:44:21 2021 -0400

    Major overhaul continued

     - rename templates
     - add checks utilities
     - add new array utilities
     - rename files
     - add assorted utilities
     - improve documentation

commit 546178fff3b526f492eb0eeffc63f79537e75de3
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Wed Oct 20 16:31:14 2021 -0400

    Update conventions

commit f6d0642f85518efda9c5d8472b99d1c14163e381
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Wed Oct 20 09:47:09 2021 -0400

    minor formatting changes

commit 2217612b55e3f9faf803a2d0c937ea2261206505
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Tue Oct 19 17:59:09 2021 -0400

    add new functions

commit 347ba7aa738dcd6a5ad9d70886b38da3a17dc89e
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Tue Oct 19 12:06:44 2021 -0400

    major overhaul

    - Add standaloneTemplate.sh
    - Rework README
    - Refactor inline documentation
    - Enforce coding standards
    - Remove CSV utilities
    - Add new array utilities
    - add _useGNUutils_
    - more ...

commit cd8e0d49aef25eeaf6b3e71a3c9e1f29ab9b06f5
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Sun Oct 17 09:56:08 2021 -0400

    Add debug functions

commit f7c5c0a3d19815dcc6ba80b5f5a2ebb77ef88b07
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Sat Oct 16 21:10:01 2021 -0400

    add new array functions

    _joinArray_, _isEmptyArray_, _sortArray_, _reverseSortArray_, and _mergearrays_

commit d8bc3d8cabdbcee3c479f97b43a45bdfe3bdafe0
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Fri Oct 15 17:27:12 2021 -0400

    add _columnize_

commit 2fd2ae9435f476bc3968c3eb0d793db4bf1d9eaf
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Mon Oct 11 22:17:45 2021 -0400

    _progressBar_: Fix unbound variable

commit e8933d15fc955a1acc665e9a081f131e681855d5
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Sun Oct 10 11:50:42 2021 -0400

    _alert_: header now underlined

commit c9ce894361dec7d3513c038794a155519baf26bc
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Tue Oct 5 09:49:42 2021 -0400

    _alert_: line numbers to gray

commit 4aaddd336ce613f629a7e6a62ef3b27ffc24d22d
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Fri Oct 8 15:05:20 2021 -0400

    _usage_ to stdout

commit e2372fc3122ec1f20acc27f04d29b3785f014e25
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Tue Oct 5 09:38:26 2021 -0400

    _setPATH_: remove unneeded logic

commit e60c75b6c954ac4bd146e2758252168027b9a43d
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Tue Oct 5 09:25:38 2021 -0400

    _findSource_: bugfix

commit 0e84912e1ccd7203e5beff9f8737f8374f4aa5d8
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Thu Sep 30 16:29:25 2021 -0400

    add requirements to documentation

commit 2c24843e3ada591e1868a94416e40b5ac0aa4994
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Thu Sep 30 15:34:10 2021 -0400

    _uniqueFilename_: improve extension handling

commit 08bc2dfdcc8632efee9179e9c960a574fc17cf0c
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Mon Sep 27 15:13:53 2021 -0400

    improve hooks script

commit 641918f1559d3b3aa38a9bbdf418938b2b81c176
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Fri Sep 24 08:16:52 2021 -0400

    _inArry_: case insensitivity

commit eae10f170680540fdb4a1222add7e54f8785ea63
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Mon Sep 20 18:31:44 2021 -0400

    clean up alerting

commit 700acd56f57fd57db84ef0e232ef41cdd7aee43c
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Mon Sep 20 18:22:11 2021 -0400

    refactor _execute_

commit d893f86900a9fed9d91a0c9cc06c13b6b34d9926
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Mon Sep 20 18:19:18 2021 -0400

    'fatal' replaces 'die'

commit 3326857bf127bef36cd9982246aa5b826d796d0a
Author: Nathaniel Landau <nate@natelandau.com>
Date:   Fri Sep 17 08:29:50 2021 -0400

    _execute_: ensure quiet and verbose work together
This commit is contained in:
Nathaniel Landau
2021-10-21 16:03:27 -04:00
parent 1e2d2ff287
commit 8bb89541e8
35 changed files with 5769 additions and 2791 deletions

View File

@@ -1,16 +1,22 @@
_setColors_() {
# DESC: Sets colors use for alerts.
# ARGS: None
# OUTS: None
# USAGE: echo "${blue}Some text${reset}"
# Functions for providing alerts to the user and logging them
if tput setaf 1 &>/dev/null; then
_setColors_() {
# DESC:
# Sets colors use for alerts.
# ARGS:
# None
# OUTS:
# None
# USAGE:
# echo "${blue}Some text${reset}"
if tput setaf 1 >/dev/null 2>&1; then
bold=$(tput bold)
underline=$(tput smul)
reverse=$(tput rev)
reset=$(tput sgr0)
if [[ $(tput colors) -ge 256 ]] 2>/dev/null; then
if [[ $(tput colors) -ge 256 ]] >/dev/null 2>&1; then
white=$(tput setaf 231)
blue=$(tput setaf 38)
yellow=$(tput setaf 11)
@@ -46,68 +52,75 @@ _setColors_() {
}
_alert_() {
# DESC: Controls all printing of messages to log files and stdout.
# ARGS: $1 (required) - The type of alert to print
# DESC:
# Controls all printing of messages to log files and stdout.
# ARGS:
# $1 (required) - The type of alert to print
# (success, header, notice, dryrun, debug, warning, error,
# fatal, info, input)
# $2 (required) - The message to be printed to stdout and/or a log file
# $3 (optional) - Pass '${LINENO}' to print the line number where the _alert_ was triggered
# OUTS: None
# USAGE: [ALERTTYPE] "[MESSAGE]" "${LINENO}"
# NOTES: The colors of each alert type are set in this function
# For specified alert types, the funcstac will be printed
# OUTS:
# stdout: The message is printed to stdout
# log file: The message is printed to a log file
# USAGE:
# [_alertType] "[MESSAGE]" "${LINENO}"
# NOTES:
# - The colors of each alert type are set in this function
# - For specified alert types, the funcstac will be printed
local function_name color
local alertType="${1}"
local message="${2}"
local line="${3:-}" # Optional line number
local _color
local _alertType="${1}"
local _message="${2}"
local _line="${3:-}" # Optional line number
if [[ -n ${line} && ${alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
message="${message} (line: ${line}) $(_functionStack_)"
elif [[ -n ${line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
message="${message} (line: ${line})"
elif [[ -z ${line} && ${alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
message="${message} $(_functionStack_)"
[[ $# -lt 2 ]] && fatal 'Missing required argument to _alert_'
if [[ -n ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
_message="${_message} ${gray}(line: ${_line}) $(_printFuncStack_)"
elif [[ -n ${_line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
_message="${_message} ${gray}(line: ${_line})"
elif [[ -z ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
_message="${_message} ${gray}$(_printFuncStack_)"
fi
if [[ ${alertType} =~ ^(error|fatal) ]]; then
color="${bold}${red}"
elif [ "${alertType}" == "info" ]; then
color="${gray}"
elif [ "${alertType}" == "warning" ]; then
color="${red}"
elif [ "${alertType}" == "success" ]; then
color="${green}"
elif [ "${alertType}" == "debug" ]; then
color="${purple}"
elif [ "${alertType}" == "header" ]; then
color="${bold}${tan}"
elif [ ${alertType} == "notice" ]; then
color="${bold}"
elif [ ${alertType} == "input" ]; then
color="${bold}${underline}"
elif [ "${alertType}" = "dryrun" ]; then
color="${blue}"
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
_color="${bold}${red}"
elif [ "${_alertType}" == "info" ]; then
_color="${gray}"
elif [ "${_alertType}" == "warning" ]; then
_color="${red}"
elif [ "${_alertType}" == "success" ]; then
_color="${green}"
elif [ "${_alertType}" == "debug" ]; then
_color="${purple}"
elif [ "${_alertType}" == "header" ]; then
_color="${bold}${white}${underline}"
elif [ ${_alertType} == "notice" ]; then
_color="${bold}"
elif [ ${_alertType} == "input" ]; then
_color="${bold}${underline}"
elif [ "${_alertType}" = "dryrun" ]; then
_color="${blue}"
else
color=""
_color=""
fi
_writeToScreen_() {
("${QUIET}") && return 0 # Print to console when script is not 'quiet'
[[ ${VERBOSE} == false && ${alertType} =~ ^(debug|verbose) ]] && return 0
[[ ${VERBOSE} == false && ${_alertType} =~ ^(debug|verbose) ]] && return 0
if ! [[ -t 1 ]]; then # Don't use colors on non-recognized terminals
color=""
if ! [[ -t 1 || -z ${TERM:-} ]]; then # Don't use colors on non-recognized terminals
_color=""
reset=""
fi
echo -e "$(date +"%r") ${color}$(printf "[%7s]" "${alertType}") ${message}${reset}"
printf "%s ${_color}[%7s] %s${reset}\n" "$(date +"%r")" "${_alertType}" "${_message}"
}
_writeToScreen_
_writeToLog_() {
[[ ${alertType} == "input" ]] && return 0
[[ ${_alertType} == "input" ]] && return 0
[[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0
if [ -z "${LOGFILE:-}" ]; then
LOGFILE="$(pwd)/$(basename "$0").log"
@@ -116,12 +129,9 @@ _alert_() {
[[ ! -f ${LOGFILE} ]] && touch "${LOGFILE}"
# Don't use colors in logs
if command -v gsed &>/dev/null; then
local cleanmessage="$(echo "${message}" | gsed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
else
local cleanmessage="$(echo "${message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
fi
echo -e "$(date +"%b %d %R:%S") $(printf "[%7s]" "${alertType}") [$(/bin/hostname)] ${cleanmessage}" >>"${LOGFILE}"
local cleanmessage="$(echo "${_message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
# Print message to log file
printf "%s [%7s] %s %s\n" "$(date +"%b %d %R:%S")" "${_alertType}" "[$(/bin/hostname)]" "${cleanmessage}" >>"${LOGFILE}"
}
# Write specified log level data to logfile
@@ -133,27 +143,27 @@ _alert_() {
_writeToLog_
;;
INFO | info | Info)
if [[ ${alertType} =~ ^(die|error|fatal|warning|info|notice|success) ]]; then
if [[ ${_alertType} =~ ^(error|fatal|warning|info|notice|success) ]]; then
_writeToLog_
fi
;;
NOTICE | notice | Notice)
if [[ ${alertType} =~ ^(die|error|fatal|warning|notice|success) ]]; then
if [[ ${_alertType} =~ ^(error|fatal|warning|notice|success) ]]; then
_writeToLog_
fi
;;
WARN | warn | Warn)
if [[ ${alertType} =~ ^(die|error|fatal|warning) ]]; then
if [[ ${_alertType} =~ ^(error|fatal|warning) ]]; then
_writeToLog_
fi
;;
ERROR | error | Error)
if [[ ${alertType} =~ ^(die|error|fatal) ]]; then
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
_writeToLog_
fi
;;
FATAL | fatal | Fatal)
if [[ ${alertType} =~ ^(die|fatal) ]]; then
if [[ ${_alertType} =~ ^fatal ]]; then
_writeToLog_
fi
;;
@@ -161,7 +171,7 @@ _alert_() {
return 0
;;
*)
if [[ ${alertType} =~ ^(die|error|fatal) ]]; then
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
_writeToLog_
fi
;;
@@ -176,30 +186,117 @@ info() { _alert_ info "${1}" "${2:-}"; }
success() { _alert_ success "${1}" "${2:-}"; }
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
input() { _alert_ input "${1}" "${2:-}"; }
header() { _alert_ header "== ${1} ==" "${2:-}"; }
header() { _alert_ header "${1}" "${2:-}"; }
debug() { _alert_ debug "${1}" "${2:-}"; }
die() {
_alert_ fatal "${1}" "${2:-}"
_safeExit_ "1"
}
fatal() {
_alert_ fatal "${1}" "${2:-}"
_safeExit_ "1"
}
_functionStack_() {
# DESC: Prints the function stack in use
# ARGS: None
# OUTS: Prints [function]:[file]:[line]
# NOTE: Does not print functions from the alert class
_printFuncStack_() {
# DESC:
# Prints the function stack in use. Used for debugging, and error reporting.
# ARGS:
# None
# OUTS:
# stdout: Prints [function]:[file]:[line]
# NOTE:
# Does not print functions from the alert class
local _i
funcStackResponse=()
_funcStackResponse=()
for ((_i = 1; _i < ${#BASH_SOURCE[@]}; _i++)); do
case "${FUNCNAME[$_i]}" in "_alert_" | "_trapCleanup_" | fatal | error | warning | notice | info | verbose | debug | dryrun | header | success | die) continue ;; esac
funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
case "${FUNCNAME[$_i]}" in "_alert_" | "_trapCleanup_" | fatal | error | warning | notice | info | debug | dryrun | header | success) continue ;; esac
_funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
done
printf "( "
printf %s "${funcStackResponse[0]}"
printf ' < %s' "${funcStackResponse[@]:1}"
printf %s "${_funcStackResponse[0]}"
printf ' < %s' "${_funcStackResponse[@]:1}"
printf ' )\n'
}
_centerOutput_() {
# DESC:
# Prints text centered in the terminal window with an optional fill character
# ARGS:
# $1 (required): Text to center
# $2 (optional): Fill character
# OUTS:
# 0 - Success
# 1 - Failure
# stdout:
# USAGE:
# _centerOutput_ "Text to print in the center" "-"
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _input="${1}"
local _symbol="${2:- }"
local _filler
local _out
local _no_ansi_out
local i
_no_ansi_out=$(_stripANSI_ "${_input}")
declare -i _str_len=${#_no_ansi_out}
declare -i _filler_len="$(((COLUMNS - _str_len) / 2))"
[[ -n ${_symbol} ]] && _symbol="${_symbol:0:1}"
for ((i = 0; i < _filler_len; i++)); do
_filler+="${_symbol}"
done
_out="${_filler}${_input}${_filler}"
[[ $(((COLUMNS - _str_len) % 2)) -ne 0 ]] && _out+="${_symbol}"
printf "%s\n" "${_out}"
}
_columnizeOutput_() {
# DESC:
# Creates a column output for key/value pairs with line wrapping for the right column (value). Attempts to wrap at a sane line length (~100 cols) on larger screens.
# ARGS:
# $1 (required): Left padding of table
# $2 (required): Width of first column
# $3 (required): Key name (left column text)
# $4 (required): Long value (right column text. Wraps around if too long)
# OUTS:
# stdout: Prints the columnized output
# NOTE:
# Long text or ANSI colors in the first column may create display issues
# USAGE:
# _columnizeOutput_ 0 30 10 "Key" "Long value text"
[[ $# -lt 5 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _leftIndent=$1
local _leftColumn=$2
local _key="$3"
local _value="$4"
local _line
local _rightIndent
if [ "$(tput cols)" -gt 180 ]; then
_rightIndent=80
elif [ "$(tput cols)" -gt 160 ]; then
_rightIndent=60
elif [ "$(tput cols)" -gt 130 ]; then
_rightIndent=30
elif [ "$(tput cols)" -gt 120 ]; then
_rightIndent=20
elif [ "$(tput cols)" -gt 110 ]; then
_rightIndent=10
else
_rightIndent=0
fi
local _rightWrapLength=$(($(tput cols) - _leftColumn - _leftIndent - _rightIndent))
local _first_line=0
while read -r _line; do
if [[ ${_first_line} -eq 0 ]]; then
_first_line=1
else
_key=" "
fi
printf "%-${_leftIndent}s%-${_leftColumn}b %b\n" "" "${_key}" "${_line}"
done <<<"$(fold -w${_rightWrapLength} -s <<<"${_value}")"
}

View File

@@ -1,98 +1,450 @@
# Functions for manipulating arrays
_dedupeArray_() {
# DESC:
# Removes duplicate array elements
# ARGS:
# $1 (Required) - Input array
# OUTS:
# stdout: Prints de-duped elements
# USAGE:
# _removeDups_ "${array[@]}"
# NOTE:
# List order may not stay the same
# CREDIT:
# https://github.com/dylanaraps/pure-bash-bible
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare -A _tmpArray
declare -a _uniqueArray
local _i
for _i in "$@"; do
{ [[ -z ${_i} || ${_tmpArray[${_i}]:-} ]]; } && continue
_uniqueArray+=("${_i}") && _tmpArray[${_i}]=x
done
printf '%s\n' "${_uniqueArray[@]}"
}
_forEachDo_() {
# DESC:
# Iterates over elements and passes each to a function
# ARGS:
# $1 (Required) - Function name to pass each item to
# OUTS:
# 0 - Success
# Return code of called function
# stdout: Output of called function
# USAGE:
# printf "%s\n" "${arr1[@]}" | _forEachDo_ "test_func"
# _forEachDo_ "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _func="${1}"
local IFS=$'\n'
local _it
while read -r _it; do
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
[ ! "$(declare -f "${_func}")" ] && fatal "${FUNCNAME[0]} could not find function ${_func}"
eval "${_func}" "'${_it}'"
fi
declare -i _ret="$?"
if [[ ${_ret} -ne 0 ]]; then
return ${_ret}
fi
done
}
_forEachValidate_() {
# DESC:
# Iterates over elements and passes each to a function for validation. Iteration stops when the function returns 1.
# ARGS:
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success)
# OUTS:
# 0 - Success
# 1 - Iteratee function fails
# USAGE:
# printf "%s\n" "${array[@]}" | _forEachValidate_ "_isAlpha_"
# _forEachValidate_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _func="${1}"
local IFS=$'\n'
local _it
while read -r _it; do
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
[ ! "$(declare -f "${_func}")" ] && fatal "${FUNCNAME[0]} could not find function ${_func}"
eval "${_func}" "'${_it}'"
fi
declare -i _ret="$?"
if [[ ${_ret} -ne 0 ]]; then
return 1
fi
done
}
_forEachFind_() {
# DESC:
# Iterates over elements, returning the first value that is validated by a function
# ARGS:
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success)
# OUTS:
# 0 - If successful
# 1 - If iteratee function fails
# stdout: First value that is validated by the function
# USAGE:
# printf "%s\n" "${array[@]}" | _forEachFind_ "_isAlpha_"
# _forEachFind_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare _func="${1}"
declare IFS=$'\n'
while read -r _it; do
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
eval "${_func}" "'${_it}'"
fi
declare -i _ret="$?"
if [[ ${_ret} == 0 ]]; then
printf "%s" "${_it}"
return 0
fi
done
return 1
}
_forEachFilter_() {
# DESC:
# Iterates over elements, returning only those that are validated by a function
# ARGS:
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success)
# OUTS:
# 0 - Success
# 1 - Failure
# stdout: Values matching the validation function
# USAGE:
# printf "%s\n" "${array[@]}" | _forEachFind_ "_isAlpha_"
# _forEachFilter_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _func="${1}"
local IFS=$'\n'
while read -r _it; do
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
eval "${_func}" "'${_it}'"
fi
declare -i _ret="$?"
if [[ ${_ret} == 0 ]]; then
printf "%s\n" "${_it}"
fi
done
}
_forEachReject_() {
# DESC:
# The opposite of _forEachFilter_. Iterates over elements, returning only those that are not validated by a function
# ARGS:
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success, 1 on failure)
# OUTS:
# 0 - Success
# stdout: Values NOT matching the validation function
# USAGE:
# printf "%s\n" "${array[@]}" | _forEachReject_ "_isAlpha_"
# _forEachReject_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _func="${1}"
local IFS=$'\n'
while read -r _it; do
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
eval "${_func}" "'${_it}'"
fi
declare -i _ret=$?
if [[ ${_ret} -ne 0 ]]; then
echo "${_it}"
fi
done
}
_forEachSome_() {
# DESC:
# Iterates over elements, returning true if any of the elements validate as true from the function.
# ARGS:
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success, 1 on failure)
# OUTS:
# 0 If match successful
# 1 If no match found
# USAGE:
# printf "%s\n" "${array[@]}" | _forEachSome_ "_isAlpha_"
# _forEachSome_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _func="${1}"
local _IFS=$'\n'
while read -r _it; do
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
eval "${_func}" "'${_it}'"
fi
declare -i _ret=$?
if [[ ${_ret} -eq 0 ]]; then
return 0
fi
done
return 1
}
_inArray_() {
# DESC: Determine if a value is in an array
# ARGS: $1 (Required) - Value to search for
# DESC:
# Determine if a value is in an array. Default is case sensitive.
# Pass -i flag to ignore case.
# ARGS:
# $1 (Required) - Value to search for
# $2 (Required) - Array written as ${ARRAY[@]}
# OUTS: true/false
# USAGE: if _inArray_ "VALUE" "${ARRAY[@]}"; then ...
# OUTS:
# 0 if true
# 1 if untrue
# USAGE:
# if _inArray_ "VALUE" "${ARRAY[@]}"; then ...
# if _inArray_ -i "VALUE" "${ARRAY[@]}"; then ...
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# -lt 2 ]] && fatal 'Missing required argument to _inArray_()!'
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local value="$1"
local opt
local _case_insensitive=false
local OPTIND=1
while getopts ":iI" opt; do
case ${opt} in
i | I) _case_insensitive=true ;;
*) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;;
esac
done
shift $((OPTIND - 1))
local _array_item
local _value="${1}"
shift
for arrayItem in "$@"; do
[[ ${arrayItem} == "${value}" ]] && return 0
for _array_item in "$@"; do
if [ ${_case_insensitive} = true ]; then
_value="$(echo "${_value}" | tr '[:upper:]' '[:lower:]')"
_array_item="$(echo "${_array_item}" | tr '[:upper:]' '[:lower:]')"
fi
[[ ${_array_item} == "${_value}" ]] && return 0
done
return 1
}
_join_() {
# DESC: Joins items together with a user specified separator
# ARGS: $1 (Required) - Separator
# $@ (Required) - Items to be joined
# OUTS: Prints joined terms
_isEmptyArray_() {
# DESC:
# Checks if an array is empty
# ARGS:
# $1 (Required) - Input array
# OUTS:
# 0 if empty
# 1 if not empty
# USAGE:
# _join_ , a "b c" d #a,b c,d
# _join_ / var local tmp #var/local/tmp
# _join_ , "${foo[@]}" #a,b,c
# NOTE: http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
# _isEmptyArray_ "${array[@]}"
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# -lt 2 ]] && fatal 'Missing required argument to _join_()!'
declare -a _array=("$@")
if [ ${#_array[@]} -eq 0 ]; then
return 0
else
return 1
fi
}
local IFS="${1}"
_joinArray_() {
# DESC:
# Joins items together with a user specified separator
# ARGS:
# $1 (Required) - Separator
# $@ (Required) - Array or space separated items to be joined
# OUTS:
# stdout: Prints joined terms
# USAGE:
# _join_ , a "b c" d #a,b c,d
# _join_ / var local tmp #var/local/tmp
# _join_ , "${foo[@]}" #a,b,c
# CREDIT:
# http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
# https://github.com/labbots/bash-utility
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _delimiter="${1}"
shift
echo "${*}"
printf "%s" "${1}"
shift
printf "%s" "${@/#/${_delimiter}}"
}
_setdiff_() {
# DESC: Return items that exist in ARRAY1 that are do not exist in ARRAY2
# ARGS: $1 (Required) - Array 1 in format ${ARRAY[*]}
# $2 (Required) - Array 2 in format ${ARRAY[*]}
# OUTS: Prints unique terms
# USAGE: _setdiff_ "${array1[*]}" "${array2[*]}"
# NOTE: http://stackoverflow.com/a/1617303/142339
_mergeArrays_() {
# DESC:
# Merges two arrays together
# ARGS:
# $1 (Required) - Array 1
# $2 (Required) - Array 2
# OUTS:
# stdout: Prints result
# USAGE:
# newarray=($(_mergeArrays_ "array1[@]" "array2[@]"))
# NOTE:
# Note that the arrays must be passed in as strings
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# -lt 2 ]] && fatal 'Missing required argument to _setdiff_()!'
local debug skip a b
if [[ $1 == 1 ]]; then
debug=1
shift
fi
if [[ "$1" ]]; then
local setdiffA setdiffB setdiffC
# shellcheck disable=SC2206
setdiffA=($1)
# shellcheck disable=SC2206
setdiffB=($2)
fi
setdiffC=()
for a in "${setdiffA[@]}"; do
skip=
for b in "${setdiffB[@]}"; do
[[ $a == "$b" ]] && skip=1 && break
done
[[ "$skip" ]] || setdiffC=("${setdiffC[@]}" "$a")
done
[[ "$debug" ]] && for a in setdiffA setdiffB setdiffC; do
#shellcheck disable=SC1087
echo "$a ($(eval echo "\${#$a[*]}")) $(eval echo "\${$a[*]}")" 1>&2
done
[[ "$1" ]] && echo "${setdiffC[@]}"
[[ $# -ne 2 ]] && fatal 'Missing required argument to _mergeArrays_'
declare -a _arr1=("${!1}")
declare -a _arr2=("${!2}")
declare _outputArray=("${_arr1[@]}" "${_arr2[@]}")
printf "%s\n" "${_outputArray[@]}"
}
_removeDupes_() {
# DESC: Removes duplicate array elements.
# ARGS: $1 (Required) - Input array
# OUTS: Prints de-duped elements to standard out
# USAGE: _removeDups_ "${array[@]}"
# NOTE: List order may not stay the same.
# https://github.com/dylanaraps/pure-bash-bible
declare -A tmp_array
_reverseSortArray_() {
# DESC:
# Sorts an array from lowest to highest (z-a9-0)
# ARGS:
# $1 (Required) - Input array
# OUTS:
# stdout: Prints result
# USAGE:
# _reverseSortArray_ "${array[@]}"
# NOTE:
# input=("c" "b" "4" "1" "2" "3" "a")
# _reverseSortArray_ "${input[@]}"
# c b a 4 3 2 1
# CREDIT:
# https://github.com/labbots/bash-utility
for i in "$@"; do
[[ $i ]] && IFS=" " tmp_array["${i:- }"]=1
done
printf '%s\n' "${!tmp_array[@]}"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare -a _array=("$@")
declare -a _sortedArray
mapfile -t _sortedArray < <(printf '%s\n' "${_array[@]}" | sort -r)
printf "%s\n" "${_sortedArray[@]}"
}
_randomArrayElement_() {
# DESC: Selects a random item from an array
# ARGS: $1 (Required) - Input array
# OUTS: Prints result
# USAGE: _randomArrayElement_ "${array[@]}"
# NOTE: https://github.com/dylanaraps/pure-bash-bible
# Usage: random_array_element "array"
local arr=("$@")
printf '%s\n' "${arr[RANDOM % $#]}"
# DESC:
# Selects a random item from an array
# ARGS:
# $1 (Required) - Input array
# OUTS:
# stdout: Prints one random element
# USAGE:
# _randomArrayElement_ "${array[@]}"
# CREDIT:
# https://github.com/dylanaraps/pure-bash-bible
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare -a _array
local _array=("$@")
printf '%s\n' "${_array[RANDOM % $#]}"
}
_setDiff_() {
# DESC:
# Return items that exist in ARRAY1 that are do not exist in ARRAY2
# ARGS:
# $1 (Required) - Array 1 (in format ARRAY[@])
# $2 (Required) - Array 2 (in format ARRAY[@])
# OUTS:
# 0 if unique elements found
# 1 if arrays are the same
# stdout: Prints unique elements
# USAGE:
# _setDiff_ "array1[@]" "array2[@]"
# mapfile -t NEW_ARRAY < <(_setDiff_ "array1[@]" "array2[@]")
# NOTE:
# Note that the arrays must be passed in as strings
# CREDIT:
# http://stackoverflow.com/a/1617303/142339
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _skip
local _a
local _b
declare -a _setdiffA=("${!1}")
declare -a _setdiffB=("${!2}")
declare -a _setdiffC=()
for _a in "${_setdiffA[@]}"; do
_skip=
for _b in "${_setdiffB[@]}"; do
if [[ ${_a} == "${_b}" ]]; then
_skip=1
break
fi
done
[[ "${_skip}" ]] || _setdiffC=("${_setdiffC[@]}" "${_a}")
done
if [[ ${#_setdiffC[@]} == 0 ]]; then
return 1
else
printf "%s\n" "${_setdiffC[@]}"
fi
}
_sortArray_() {
# DESC:
# Sorts an array from lowest to highest (0-9 a-z)
# ARGS:
# $1 (Required) - Input array
# OUTS:
# stdout: Prints result
# USAGE:
# _sortArray_ "${array[@]}"
# NOTE:
# input=("c" "b" "4" "1" "2" "3" "a")
# _sortArray_ "${input[@]}"
# 1 2 3 4 a b c
# CREDIT:
# https://github.com/labbots/bash-utility
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare -a _array=("$@")
declare -a _sortedArray
mapfile -t _sortedArray < <(printf '%s\n' "${_array[@]}" | sort)
printf "%s\n" "${_sortedArray[@]}"
}

View File

@@ -1,373 +0,0 @@
_execute_() {
# DESC: Executes commands with safety and logging options
# ARGS: $1 (Required) - The command to be executed. Quotation marks MUST be escaped.
# $2 (Optional) - String to display after command is executed
# OPTS: -v Always print debug output from the execute function
# -n Use NOTICE level alerting (default is INFO)
# -p Pass a failed command with 'return 0'. This effectively bypasses set -e.
# -e Bypass _alert_ functions and use 'echo RESULT'
# -s Use '_alert_ success' for successful output. (default is 'info')
# -q Do not print output (QUIET mode)
# OUTS: None
# USE : _execute_ "cp -R \"~/dir/somefile.txt\" \"someNewFile.txt\"" "Optional message"
# _execute_ -sv "mkdir \"some/dir\""
# NOTE:
# If $DRYRUN=true no commands are executed
# If $VERBOSE=true the command's native output is printed to
# stderr and stdin. This can be forced with `_execute_ -v`
local LOCAL_VERBOSE=false
local PASS_FAILURES=false
local ECHO_RESULT=false
local SUCCESS_RESULT=false
local QUIET_RESULT=false
local NOTICE_RESULT=false
local opt
local OPTIND=1
while getopts ":vVpPeEsSqQnN" opt; do
case $opt in
v | V) LOCAL_VERBOSE=true ;;
p | P) PASS_FAILURES=true ;;
e | E) ECHO_RESULT=true ;;
s | S) SUCCESS_RESULT=true ;;
q | Q) QUIET_RESULT=true ;;
n | N) NOTICE_RESULT=true ;;
*)
{
error "Unrecognized option '$1' passed to _execute_. Exiting."
_safeExit_
}
;;
esac
done
shift $((OPTIND - 1))
local CMD="${1:?_execute_ needs a command}"
local EXECUTE_MESSAGE="${2:-$1}"
local SAVE_VERBOSE=${VERBOSE}
if "${LOCAL_VERBOSE}"; then
VERBOSE=true
fi
if "${DRYRUN}"; then
if "${QUIET_RESULT}"; then
VERBOSE=$SAVE_VERBOSE
return 0
fi
if [ -n "${2:-}" ]; then
dryrun "${1} (${2})" "$(caller)"
else
dryrun "${1}" "$(caller)"
fi
elif ${VERBOSE}; then
if eval "${CMD}"; then
if "${QUIET_RESULT}"; then
VERBOSE=${SAVE_VERBOSE}
return 0
elif "${ECHO_RESULT}"; then
echo "${EXECUTE_MESSAGE}"
elif "${SUCCESS_RESULT}"; then
success "${EXECUTE_MESSAGE}"
elif "${NOTICE_RESULT}"; then
notice "${EXECUTE_MESSAGE}"
else
info "${EXECUTE_MESSAGE}"
fi
VERBOSE=${SAVE_VERBOSE}
return 0
else
if "${ECHO_RESULT}"; then
echo "warning: ${EXECUTE_MESSAGE}"
else
warning "${EXECUTE_MESSAGE}"
fi
VERBOSE=${SAVE_VERBOSE}
"${PASS_FAILURES}" && return 0 || return 1
fi
else
if eval "${CMD}" &>/dev/null; then
if "${QUIET_RESULT}"; then
VERBOSE=${SAVE_VERBOSE}
return 0
elif "${ECHO_RESULT}"; then
echo "${EXECUTE_MESSAGE}"
elif "${SUCCESS_RESULT}"; then
success "${EXECUTE_MESSAGE}"
elif "${NOTICE_RESULT}"; then
notice "${EXECUTE_MESSAGE}"
else
info "${EXECUTE_MESSAGE}"
fi
VERBOSE=${SAVE_VERBOSE}
return 0
else
if "${ECHO_RESULT}"; then
echo "error: ${EXECUTE_MESSAGE}"
else
warning "${EXECUTE_MESSAGE}"
fi
VERBOSE=${SAVE_VERBOSE}
"${PASS_FAILURES}" && return 0 || return 1
fi
fi
}
_findBaseDir_() {
# DESC: Locates the real directory of the script being run. Similar to GNU readlink -n
# ARGS: None
# OUTS: Echo result to STDOUT
# USE : baseDir="$(_findBaseDir_)"
# cp "$(_findBaseDir_ "somefile.txt")" "other_file.txt"
local SOURCE
local DIR
# Is file sourced?
[[ $_ != "$0" ]] \
&& SOURCE="${BASH_SOURCE[1]}" \
|| SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="${DIR}/${SOURCE}" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
echo "$(cd -P "$(dirname "${SOURCE}")" && pwd)"
}
_checkBinary_() {
# DESC: Check if a binary exists in the search PATH
# ARGS: $1 (Required) - Name of the binary to check for existence
# OUTS: true/false
# USAGE: (_checkBinary_ ffmpeg ) && [SUCCESS] || [FAILURE]
if [[ $# -lt 1 ]]; then
error 'Missing required argument to _checkBinary_()!'
return 1
fi
if ! command -v "$1" >/dev/null 2>&1; then
debug "Did not find dependency: '$1'"
return 1
fi
return 0
}
_haveFunction_() {
# DESC: Tests if a function exists.
# ARGS: $1 (Required) - Function name
# OUTS: true/false
local f
f="$1"
if declare -f "${f}" &>/dev/null 2>&1; then
return 0
else
return 1
fi
}
_pauseScript_() {
# DESC: Pause a script at any point and continue after user input
# ARGS: $1 (Optional) - String for customized message
# OUTS: None
local pauseMessage
pauseMessage="${1:-Paused}. Ready to continue?"
if _seekConfirmation_ "${pauseMessage}"; then
info "Continuing..."
else
notice "Exiting Script"
_safeExit_
fi
}
_progressBar_() {
# DESC: Prints a progress bar within a for/while loop
# ARGS: $1 (Required) - The total number of items counted
# $2 (Optional) - The optional title of the progress bar
# OUTS: None
# USAGE:
# for number in $(seq 0 100); do
# sleep 1
# _progressBar_ "100" "Counting numbers"
# done
($QUIET) && return
($VERBOSE) && return
[ ! -t 1 ] && return # Do nothing if the output is not a terminal
[ $1 == 1 ] && return # Do nothing with a single element
local width bar_char perc num bar progressBarLine barTitle n
n="${1:?_progressBar_ needs input}"
((n = n - 1))
barTitle="${2:-Running Process}"
width=30
bar_char="#"
# Reset the count
[ -z "${progressBarProgress}" ] && progressBarProgress=0
tput civis # Hide the cursor
trap 'tput cnorm; exit 1' SIGINT
if [ ! "${progressBarProgress}" -eq $n ]; then
#echo "progressBarProgress: $progressBarProgress"
# Compute the percentage.
perc=$((progressBarProgress * 100 / $1))
# Compute the number of blocks to represent the percentage.
num=$((progressBarProgress * width / $1))
# Create the progress bar string.
bar=""
if [ ${num} -gt 0 ]; then
bar=$(printf "%0.s${bar_char}" $(seq 1 ${num}))
fi
# Print the progress bar.
progressBarLine=$(printf "%s [%-${width}s] (%d%%)" " ${barTitle}" "${bar}" "${perc}")
echo -ne "${progressBarLine}\r"
progressBarProgress=$((progressBarProgress + 1))
else
# Clear the progress bar when complete
# echo -ne "\033[0K\r"
tput el # Clear the line
unset progressBarProgress
fi
tput cnorm
}
_rootAvailable_() {
# DESC: Validate we have superuser access as root (via sudo if requested)
# ARGS: $1 (optional): Set to any value to not attempt root access via sudo
# OUTS: None
# NOTE: https://github.com/ralish/bash-script-template
local superuser
if [[ ${EUID} -eq 0 ]]; then
superuser=true
elif [[ -z ${1:-} ]]; then
if command -v sudo &>/dev/null; then
debug 'Sudo: Updating cached credentials ...'
if ! sudo -v; then
warning "Sudo: Couldn't acquire credentials ..."
else
local test_euid
test_euid="$(sudo -H -- "$BASH" -c 'printf "%s" "$EUID"')"
if [[ ${test_euid} -eq 0 ]]; then
superuser=true
fi
fi
fi
fi
if [[ -z ${superuser:-} ]]; then
debug 'Unable to acquire superuser credentials.'
return 1
fi
debug 'Successfully acquired superuser credentials.'
return 0
}
_runAsRoot_() {
# DESC: Run the requested command as root (via sudo if requested)
# ARGS: $1 (optional): Set to zero to not attempt execution via sudo
# $@ (required): Passed through for execution as root user
# OUTS: None
# NOTE: https://github.com/ralish/bash-script-template
if [[ $# -eq 0 ]]; then
fatal 'Missing required argument to _runAsRoot_()!'
fi
if [[ ${1:-} =~ ^0$ ]]; then
local skip_sudo=true
shift
fi
if [[ ${EUID} -eq 0 ]]; then
"$@"
elif [[ -z ${skip_sudo:-} ]]; then
sudo -H -- "$@"
else
fatal "Unable to run requested command as root: $*"
fi
}
_seekConfirmation_() {
# DESC: Seek user input for yes/no question
# ARGS: $1 (Optional) - Question being asked
# OUTS: true/false
# USAGE: _seekConfirmation_ "Do something?" && echo "okay" || echo "not okay"
# OR
# if _seekConfirmation_ "Answer this question"; then
# something
# fi
local yn
input "${1:-}"
if "${FORCE}"; then
debug "Forcing confirmation with '--force' flag set"
echo -e ""
return 0
else
while true; do
read -r -p " (y/n) " yn
case $yn in
[Yy]*) return 0 ;;
[Nn]*) return 1 ;;
*) input "Please answer yes or no." ;;
esac
done
fi
}
_setPATH_() {
# DESC: Add directories to $PATH so script can find executables
# ARGS: $@ - One or more paths
# OUTS: $PATH
# USAGE: _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)"
local NEWPATH NEWPATHS USERPATH
for USERPATH in "$@"; do
NEWPATHS+=("$USERPATH")
done
for NEWPATH in "${NEWPATHS[@]}"; do
if [ -d "${NEWPATH}" ]; then
if ! echo "$PATH" | grep -Eq "(^|:)${NEWPATH}($|:)"; then
PATH="${NEWPATH}:${PATH}"
debug "Added '${NEWPATH}' to PATH"
fi
fi
done
}
_safeExit_() {
# DESC: Cleanup and exit from a script
# ARGS: $1 (optional) - Exit code (defaults to 0)
# OUTS: None
if [[ -d ${SCRIPT_LOCK:-} ]]; then
if command rm -rf "${SCRIPT_LOCK}"; then
debug "Removing script lock"
else
warning "Script lock could not be removed. Try manually deleting ${tan}'${LOCK_DIR}'${red}"
fi
fi
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
command rm -r "${TMP_DIR}"
else
command rm -r "${TMP_DIR}"
debug "Removing temp directory"
fi
fi
trap - INT TERM EXIT
exit ${1:-0}
}

352
utilities/checks.bash Normal file
View File

@@ -0,0 +1,352 @@
# Functions for validating common use-cases
_binaryExists_() {
# DESC:
# Check if a binary exists in the search PATH
# ARGS:
# $1 (Required) - Name of the binary to check for existence
# OUTS:
# 0 if true
# 1 if false
# USAGE:
# (_binaryExists_ ffmpeg ) && [SUCCESS] || [FAILURE]
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
if ! command -v "$1" >/dev/null 2>&1; then
debug "Did not find dependency: '${1}'"
return 1
fi
return 0
}
_functionExists_() {
# DESC:
# Tests if a function exists in the current scope
# ARGS:
# $1 (Required) - Function name
# OUTS:
# 0 if function exists
# 1 if function does not exist
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _testFunction
_testFunction="${1}"
if declare -f "${_testFunction}" &>/dev/null 2>&1; then
return 0
else
return 1
fi
}
_isAlpha_() {
# DESC:
# Validate that a given input is entirely alphabetic characters
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Input is only alphabetic characters
# 1 - Input contains non-alphabetic characters
# USAGE:
# _isAlpha_ "${var}"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _re='^[[:alpha:]]+$'
if [[ ${1} =~ ${_re} ]]; then
return 0
fi
return 1
}
_isAlphaNum_() {
# DESC:
# Validate that a given input is entirely alpha-numeric characters
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Input is only alpha-numeric characters
# 1 - Input contains alpha-numeric characters
# USAGE:
# _isAlphaNum_ "${var}"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _re='^[[:alnum:]]+$'
if [[ ${1} =~ ${_re} ]]; then
return 0
fi
return 1
}
_isAlphaDash_() {
# DESC:
# Validate that a given input contains only alpha-numeric characters, as well as dashes and underscores.
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Input is only alpha-numeric or dash or underscore characters
# 1 - Input is not only alpha-numeric or dash or underscore characters
# USAGE:
# _isAlphaDash_ "${var}"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _re='^[[:alnum:]_-]+$'
if [[ ${1} =~ ${_re} ]]; then
return 0
fi
return 1
}
_isEmail_() {
# DESC:
# Validates that input is a valid email address
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Is valid email
# 1 - Is not valid email
# USAGE:
# _isEmail_ "somename+test@gmail.com"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _emailRegex
_emailRegex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$"
[[ ${1} =~ ${_emailRegex} ]] && return 0 || return 1
}
_isInternetAvailable_() {
# DESC:
# Check if internet connection is available
# ARGS:
# None
# OUTS:
# 0 - Success: Internet connection is available
# 1 - Failure: Internet connection is not available
# stdout:
# USAGE:
# _isInternetAvailable_
# NOTES:
#
local _checkInternet
if [[ -t 1 || -z ${TERM} ]]; then
_checkInternet="$(sh -ic 'exec 3>&1 2>/dev/null; { curl --compressed -Is google.com 1>&3; kill 0; } | { sleep 10; kill 0; }' || :)"
else
_checkInternet="$(curl --compressed -Is google.com -m 10)"
fi
if [[ -z ${_checkInternet:-} ]]; then
return 1
fi
}
_isIPv4_() {
# DESC:
# Validates that input is a valid IP version 4 address
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Is valid IPv4 address
# 1 - Is not valid IPv4 address
# USAGE:
# _isIPv4_ "192.168.1.1"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _ip="${1}"
local IFS=.
# shellcheck disable=SC2206
declare -a _a=(${_ip})
[[ ${_ip} =~ ^[0-9]+(\.[0-9]+){3}$ ]] || return 1
# Test values of quads
local _quad
for _quad in {0..3}; do
[[ ${_a[${_quad}]} -gt 255 ]] && return 1
done
return 0
}
_isFile_() {
# DESC:
# Validate that a given input points to a valid file
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Input is a valid file
# 1 - Input is not a valid file
# USAGE:
# _varIsFile_ "${var}"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
[[ -f ${1} ]] && return 0 || return 1
}
_isDir_() {
# DESC:
# Validate that a given input points to a valid directory
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Input is a directory
# 1 - Input is not a directory
# USAGE:
# _varIsDir_ "${var}"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
[[ -d ${1} ]] && return 0 || return 1
}
_isNum_() {
# DESC:
# Validate that a given input is entirely numeric characters
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Input is only numeric characters
# 1 - Input contains numeric characters
# USAGE:
# _isNum_ "${var}"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _re='^[[:digit:]]+$'
if [[ ${1} =~ ${_re} ]]; then
return 0
fi
return 1
}
_isTerminal_() {
# DESC:
# Check is script is run in an interactive terminal
# ARGS:
# None
# OUTS:
# 0 - Script is run in a terminal
# 1 - Script is not run in a terminal
# USAGE:
# _isTerminal_
[[ -t 1 || -z ${TERM} ]] && return 0 || return 1
}
_rootAvailable_() {
# DESC:
# Validate we have superuser access as root (via sudo if requested)
# ARGS:
# $1 (optional): Set to any value to not attempt root access via sudo
# OUTS:
# 0 if true
# 1 if false
# CREDIT:
# https://github.com/ralish/bash-script-template
local _superuser
local _testEUID
if [[ ${EUID} -eq 0 ]]; then
_superuser=true
elif [[ -z ${1:-} ]]; then
if command -v sudo >/dev/null 2>&1; then
debug 'Sudo: Updating cached credentials ...'
if ! sudo -v; then
warning "Sudo: Couldn't acquire credentials ..."
else
_testEUID="$(sudo -H -- "$BASH" -c 'printf "%s" "$EUID"')"
if [[ ${_testEUID} -eq 0 ]]; then
_superuser=true
fi
fi
fi
fi
if [[ -z ${superuser:-} ]]; then
debug 'Unable to acquire superuser credentials.'
return 1
fi
debug 'Successfully acquired superuser credentials.'
return 0
}
_varIsTrue_() {
# DESC:
# Check if a given variable is true
# ARGS:
# $1 (required): Variable to check
# OUTS:
# 0 - Variable is true
# 1 - Variable is false
# USAGE
# _varIsTrue_ "${var}"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
[[ ${1} == true || ${1} -eq 0 ]] && return 0 || return 1
}
_varIsFalse_() {
# DESC:
# Check if a given variable is false
# ARGS:
# $1 (required): Variable to check
# OUTS:
# 0 - Variable is false
# 1 - Variable is true
# USAGE
# _varIsFalse_ "${var}"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
[[ ${1} == false || ${1} -eq 1 ]] && return 0 || return 1
}
_varIsEmpty_() {
# DESC:
# Check if given variable is empty or null.
# ARGS:
# $1 (required): Variable to check
# OUTS:
# 0 - Variable is empty or null
# 1 - Variable is not empty or null
# USAGE
# _varIsEmpty_ "${var}"
[[ -z ${1} || ${1} == "null" ]] && return 0 || return 1
}
_isIPv6_() {
# DESC:
# Validates that input is a valid IP version 46address
# ARGS:
# $1 (required): Input to check
# OUTS:
# 0 - Is valid IPv6 address
# 1 - Is not valid IPv6 address
# USAGE:
# _isIPv6_ "2001:db8:85a3:8d3:1319:8a2e:370:7348"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _ip="${1}"
local _re="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|\
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|\
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|\
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|\
:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|\
::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|\
(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|\
(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
[[ ${_ip} =~ ${_re} ]] && return 0 || return 1
}

View File

@@ -1,34 +0,0 @@
_makeCSV_() {
# Creates a new CSV file if one does not already exist
# Takes passed arguments and writes them as a header line to the CSV
# Usage '_makeCSV_ column1 column2 column3'
# Set the location and name of the CSV File
if [ -z "${csvLocation}" ]; then
csvLocation="${HOME}/Desktop"
fi
if [ -z "${csvName}" ]; then
csvName="$(LC_ALL=C date +%Y-%m-%d)-${FUNCNAME[1]}.csv"
fi
csvFile="${csvLocation}/${csvName}"
# Overwrite existing file? If not overwritten, new content is added
# to the bottom of the existing file
if [ -f "${csvFile}" ]; then
if _seekConfirmation_ "${csvFile} already exists. Overwrite?"; then
rm "${csvFile}"
fi
fi
_writeCSV_ "$@"
}
_writeCSV_() {
# Takes passed arguments and writes them as a comma separated line
# Usage '_writeCSV_ column1 column2 column3'
local csvInput=("$@")
saveIFS=$IFS
IFS=','
echo "${csvInput[*]}" >>"${csvFile}"
IFS=${saveIFS}
}

View File

@@ -1,73 +1,216 @@
# Functions to help work with dates and time
_convertToUnixTimestamp_() {
# DESC:
# Convert date string to unix timestamp
# ARGS:
# $1 (Required) - Date to be converted
# OUTS:
# 0 If successful
# 1 If failed to convert
# stdout: timestamp for specified date/time
# USAGE:
# printf "%s\n" "$(_convertToUnixTimestamp_ "Jan 10, 2019")"
# NOTES:
#
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _date
_date=$(date -d "${1}" +"%s") || return 1
printf "%s\n" "${_date}"
}
_countdown_() {
# DESC:
# Sleep for a specified amount of time
# ARGS:
# $1 (Optional) - Total seconds to sleep for(Default is 10)
# $2 (Optional) - Increment to count down
# $3 (Optional) - Message to print at each increment (default is ...)
# OUTS:
# stdout: Prints the message at each increment
# USAGE:
# _countdown_ 10 1 "Waiting for cache to invalidate"
local i ii t
local _n=${1:-10}
local _sleepTime=${2:-1}
local _message="${3:-...}"
((t = _n + 1))
for ((i = 1; i <= _n; i++)); do
((ii = t - i))
if declare -f "info" &>/dev/null 2>&1; then
info "${_message} ${ii}"
else
echo "${_message} ${ii}"
fi
sleep ${_sleepTime}
done
}
_dateUnixTimestamp_() {
# DESC:
# Get the current time in unix timestamp
# ARGS:
# None
# OUTS:
# stdout: Prints result ~ 1591554426
# 0 If successful
# 1 If failed to get timestamp
# USAGE:
# _dateUnixTimestamp_
local _now
_now="$(date --universal +%s)" || return 1
printf "%s\n" "${_now}"
}
_formatDate_() {
# DESC:
# Reformats dates into user specified formats
# ARGS:
# $1 (Required) - Date to be formatted
# $2 (Optional) - Format in any format accepted by bash's date command.
# Examples:
# %F - YYYY-MM-DD
# %D - MM/DD/YY
# %a - Name of weekday in short (like Sun, Mon, Tue, Wed, Thu, Fri, Sat)
# %A - Name of weekday in full (like Sunday, Monday, Tuesday)
# '+%m %d, %Y' - 12 27, 2019
# OUTS:
# stdout: Prints result
# USAGE:
# _formatDate_ "Jan 10, 2019" "%D"
# NOTE:
# Defaults to YYYY-MM-DD or $(date +%F)
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _d="${1}"
local _format="${2:-%F}"
_format="${_format//+/}"
date -d "${_d}" "+${_format}"
}
_fromSeconds_() {
# DESC:
# Convert seconds to HH:MM:SS
# ARGS:
# $1 (Required) - Time in seconds
# OUTS:
# stdout: HH:MM:SS
# USAGE:
# _fromSeconds_ "SECONDS"
# EXAMPLE:
# To compute the time it takes a script to run:
# STARTTIME=$(date +"%s")
# ENDTIME=$(date +"%s")
# TOTALTIME=$(($ENDTIME-$STARTTIME)) # human readable time
# _fromSeconds_ "$TOTALTIME"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _h
local _m
local _s
((_h = ${1} / 3600))
((_m = (${1} % 3600) / 60))
((_s = ${1} % 60))
printf "%02d:%02d:%02d\n" ${_h} ${_m} ${_s}
}
_monthToNumber_() {
# DESC: Convert a month name to a number
# ARGS: None
# OUTS: Prints the number of the month to stdout
# USAGE: _monthToNumber_ "January"
# DESC:
# Convert a month name to a number
# ARGS:
# $1 (Required) - Month name
# OUTS:
# stdout: Prints the number of the month (1-12)
# USAGE:
# _monthToNumber_ "January"
local mon="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
case "$mon" in
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _mon="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
case "${_mon}" in
january | jan | ja) echo 1 ;;
february | feb | fe) echo 2 ;;
march | mar | ma) echo 3 ;;
april | apr | ap) echo 4 ;;
may) echo 5 ;;
may) echo 5 ;;
june | jun | ju) echo 6 ;;
july | jul) echo 7 ;;
july | jul) echo 7 ;;
august | aug | au) echo 8 ;;
september | sep | se) echo 9 ;;
october | oct) echo 10 ;;
october | oct | oc) echo 10 ;;
november | nov | no) echo 11 ;;
december | dec | de) echo 12 ;;
*)
warning "month_monthToNumber_: Bad monthname: $1"
warning "_monthToNumber_: Bad month name: ${_mon}"
return 1
;;
;;
esac
}
_numberToMonth_() {
# DESC: Convert a month number to its name
# ARGS: None
# OUTS: Prints the name of the month to stdout
# USAGE: _numberToMonth_ 1
# DESC:
# Convert a month number to its name
# ARGS:
# $1 (Required) - Month number (1-12)
# OUTS:
# stdout: Prints the name of the month
# USAGE:
# _numberToMonth_ 11
local mon="$1"
case "$mon" in
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _mon="$1"
case "${_mon}" in
1 | 01) echo January ;;
2 | 02) echo February ;;
3 | 03) echo March ;;
4 | 04) echo April ;;
5 | 05) echo May ;;
5 | 05) echo May ;;
6 | 06) echo June ;;
7 | 07) echo July ;;
8 | 08) echo August ;;
9 | 09) echo September ;;
10) echo October ;;
10) echo October ;;
11) echo November ;;
12) echo December ;;
*)
warning "_numberToMonth_: Bad month number: $1"
warning "_numberToMonth_: Bad month number: ${_mon}"
return 1
;;
;;
esac
}
_parseDate_() {
# DESC: Takes a string as input and attempts to find a date within it
# to parse into component parts (day, month, year)
# ARGS: $1 (required) - A string
# OUTS: Returns error if no date found
# $_parseDate_found - The date found in the string
# $_parseDate_year - The year
# $_parseDate_month - The number month
# $_parseDate_monthName - The name of the month
# $_parseDate_day - The day
# $_parseDate_hour - The hour (if avail)
# $_parseDate_minute - The minute (if avail)
# USAGE: if _parseDate_ "[STRING]"; then ...
# NOTE: This function only recognizes dates from the year 2000 to 2029
# NOTE: Will recognize dates in the following formats separated by '-_ ./'
# DESC:
# Takes a string as input and attempts to find a date within it to parse
# into component parts (day, month, year)
# ARGS:
# $1 (required) - A string
# OUTS:
# 0 if date is found
# 1 if date is NOT found
# If a date was found, the following variables are set:
# $PARSE_DATE_FOUND - The date found in the string
# $PARSE_DATE_YEAR - The year
# $PARSE_DATE_MONTH - The number month
# $PARSE_DATE_MONTH_NAME - The name of the month
# $PARSE_DATE_DAY - The day
# $PARSE_DATE_HOUR - The hour (if avail)
# $PARSE_DATE_MINUTE - The minute (if avail)
# USAGE:
# if _parseDate_ "[STRING]"; then ...
# NOTE:
# - This function only recognizes dates from the year 2000 to 202
# - Will recognize dates in the following formats separated by '-_ ./'
# * YYYY-MM-DD * Month DD, YYYY * DD Month, YYYY
# * Month, YYYY * Month, DD YY * MM-DD-YYYY
# * MMDDYYYY * YYYYMMDD * DDMMYYYY
@@ -77,124 +220,122 @@ _parseDate_() {
# * MMDDYY * YYMMDD * mon-DD-YY
# TODO: Simplify and reduce the number of regex checks
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
[[ $# -eq 0 ]] && {
error 'Missing required argument to _parseDate_()!'
return 1
}
local _stringToTest="${1}"
local _pat
local date="${1:-$(date +%F)}"
_parseDate_found="" _parseDate_year="" _parseDate_month="" _parseDate_monthName=""
_parseDate_day="" _parseDate_hour="" _parseDate_minute=""
PARSE_DATE_FOUND="" PARSE_DATE_YEAR="" PARSE_DATE_MONTH="" PARSE_DATE_MONTH_NAME=""
PARSE_DATE_DAY="" PARSE_DATE_HOUR="" PARSE_DATE_MINUTE=""
shopt -s nocasematch #Use case-insensitive regex
debug "_parseDate_() input ${tan}$date${purple}"
# YYYY MM DD or YYYY-MM-DD
pat="(.*[^0-9]|^)((20[0-2][0-9])[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2}))([^0-9].*|$)"
if [[ ${date} =~ $pat ]]; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year=$((10#${BASH_REMATCH[3]}))
_parseDate_month=$((10#${BASH_REMATCH[4]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[5]}))
_pat="(.*[^0-9]|^)((20[0-2][0-9])[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2}))([^0-9].*|$)"
if [[ ${_stringToTest} =~ ${_pat} ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[5]}))
debug "regex match: ${tan}YYYY-MM-DD${purple}"
# Month DD, YYYY
elif [[ ${date} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec)[-\./_ ]+([0-9]{1,2})(nd|rd|th|st)?,?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
_parseDate_found="${BASH_REMATCH[1]:-}"
_parseDate_month=$(_monthToNumber_ ${BASH_REMATCH[2]:-})
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month:-}")"
_parseDate_day=$((10#${BASH_REMATCH[3]:-}))
_parseDate_year=$((10#${BASH_REMATCH[5]:-}))
elif [[ ${_stringToTest} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec)[-\./_ ]+([0-9]{1,2})(nd|rd|th|st)?,?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[1]:-}"
PARSE_DATE_MONTH=$(_monthToNumber_ ${BASH_REMATCH[2]:-})
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH:-}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]:-}))
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]:-}))
debug "regex match: ${tan}Month DD, YYYY${purple}"
# Month DD, YY
elif [[ ${date} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec)[-\./_ ]+([0-9]{1,2})(nd|rd|th|st)?,?[-\./_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
_parseDate_found="${BASH_REMATCH[1]}"
_parseDate_month=$(_monthToNumber_ ${BASH_REMATCH[2]})
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[3]}))
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
elif [[ ${_stringToTest} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec)[-\./_ ]+([0-9]{1,2})(nd|rd|th|st)?,?[-\./_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
PARSE_DATE_MONTH=$(_monthToNumber_ ${BASH_REMATCH[2]})
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
debug "regex match: ${tan}Month DD, YY${purple}"
# DD Month YYYY
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{2})[-\./_ ]+(january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec),?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day=$((10#"${BASH_REMATCH[3]}"))
_parseDate_month="$(_monthToNumber_ "${BASH_REMATCH[4]}")"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year=$((10#"${BASH_REMATCH[5]}"))
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{2})[-\./_ ]+(january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec),?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY=$((10#"${BASH_REMATCH[3]}"))
PARSE_DATE_MONTH="$(_monthToNumber_ "${BASH_REMATCH[4]}")"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR=$((10#"${BASH_REMATCH[5]}"))
debug "regex match: ${tan}DD Month, YYYY${purple}"
# MM-DD-YYYY or DD-MM-YYYY
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
if [[ $((10#${BASH_REMATCH[3]})) -lt 13 &&
$((10#${BASH_REMATCH[4]})) -gt 12 &&
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year=$((10#${BASH_REMATCH[5]}))
_parseDate_month=$((10#${BASH_REMATCH[3]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]}))
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
debug "regex match: ${tan}MM-DD-YYYY${purple}"
elif [[ $((10#${BASH_REMATCH[3]})) -gt 12 &&
$((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
$((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year=$((10#${BASH_REMATCH[5]}))
_parseDate_month=$((10#${BASH_REMATCH[4]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]}))
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]}))
debug "regex match: ${tan}DD-MM-YYYY${purple}"
elif [[ $((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year=$((10#${BASH_REMATCH[5]}))
_parseDate_month=$((10#${BASH_REMATCH[3]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]}))
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
debug "regex match: ${tan}MM-DD-YYYY${purple}"
else
shopt -u nocasematch
return 1
fi
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
if [[ $((10#${BASH_REMATCH[3]})) -lt 13 &&
$((10#${BASH_REMATCH[4]})) -gt 12 &&
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
_parseDate_month=$((10#${BASH_REMATCH[3]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
debug "regex match: ${tan}MM-DD-YYYY${purple}"
elif [[ $((10#${BASH_REMATCH[3]})) -gt 12 &&
$((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
$((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
_parseDate_month=$((10#${BASH_REMATCH[4]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]}))
debug "regex match: ${tan}DD-MM-YYYY${purple}"
elif [[ $((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
_parseDate_month=$((10#${BASH_REMATCH[3]}))
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_day=$((10#${BASH_REMATCH[4]}))
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
debug "regex match: ${tan}MM-DD-YYYY${purple}"
else
shopt -u nocasematch
@@ -202,124 +343,124 @@ _parseDate_() {
fi
# Month, YYYY
elif [[ ${date} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec),?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
_parseDate_found="${BASH_REMATCH[1]}"
_parseDate_day="1"
_parseDate_month="$(_monthToNumber_ "${BASH_REMATCH[2]}")"
_parseDate_monthName="$(_numberToMonth_ $_parseDate_month)"
_parseDate_year="$((10#${BASH_REMATCH[3]}))"
elif [[ ${_stringToTest} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec),?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
PARSE_DATE_DAY="1"
PARSE_DATE_MONTH="$(_monthToNumber_ "${BASH_REMATCH[2]}")"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ $PARSE_DATE_MONTH)"
PARSE_DATE_YEAR="$((10#${BASH_REMATCH[3]}))"
debug "regex match: ${tan}Month, YYYY${purple}"
# YYYYMMDDHHMM
elif [[ ${date} =~ (.*[^0-9]|^)((20[0-2][0-9])([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[5]}))"
_parseDate_month="$((10#${BASH_REMATCH[4]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="$((10#${BASH_REMATCH[3]}))"
_parseDate_hour="$((10#${BASH_REMATCH[6]}))"
_parseDate_minute="$((10#${BASH_REMATCH[7]}))"
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)((20[0-2][0-9])([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[4]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="$((10#${BASH_REMATCH[3]}))"
PARSE_DATE_HOUR="$((10#${BASH_REMATCH[6]}))"
PARSE_DATE_MINUTE="$((10#${BASH_REMATCH[7]}))"
debug "regex match: ${tan}YYYYMMDDHHMM${purple}"
# YYYYMMDDHH 1 2 3 4 5 6
elif [[ ${date} =~ (.*[^0-9]|^)((20[0-2][0-9])([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[5]}))"
_parseDate_month="$((10#${BASH_REMATCH[4]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="$((10#${BASH_REMATCH[3]}))"
_parseDate_hour="${BASH_REMATCH[6]}"
_parseDate_minute="00"
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)((20[0-2][0-9])([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[4]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="$((10#${BASH_REMATCH[3]}))"
PARSE_DATE_HOUR="${BASH_REMATCH[6]}"
PARSE_DATE_MINUTE="00"
debug "regex match: ${tan}YYYYMMDDHHMM${purple}"
# MMDDYYYY or YYYYMMDD or DDMMYYYY
# 1 2 3 4 5 6
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
# MMDDYYYY
if [[ $((10#${BASH_REMATCH[5]})) -eq 20 &&
$((10#${BASH_REMATCH[3]})) -lt 13 &&
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
$((10#${BASH_REMATCH[3]})) -lt 13 &&
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[4]}))"
_parseDate_month="$((10#${BASH_REMATCH[3]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
debug "regex match: ${tan}MMDDYYYY${purple}"
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[4]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[3]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
debug "regex match: ${tan}MMDDYYYY${purple}"
# DDMMYYYY
elif [[ $((10#${BASH_REMATCH[5]})) -eq 20 &&
$((10#${BASH_REMATCH[3]})) -gt 12 &&
$((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
$((10#${BASH_REMATCH[3]})) -gt 12 &&
$((10#${BASH_REMATCH[3]})) -lt 32 &&
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[3]}))"
_parseDate_month="$((10#${BASH_REMATCH[4]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
debug "regex match: ${tan}DDMMYYYY${purple}"
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[3]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[4]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
debug "regex match: ${tan}DDMMYYYY${purple}"
# YYYYMMDD
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
$((10#${BASH_REMATCH[6]})) -gt 12 &&
$((10#${BASH_REMATCH[6]})) -lt 32 &&
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
$((10#${BASH_REMATCH[6]})) -gt 12 &&
$((10#${BASH_REMATCH[6]})) -lt 32 &&
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[6]}))"
_parseDate_month="$((10#${BASH_REMATCH[5]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
debug "regex match: ${tan}YYYYMMDD${purple}"
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[6]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
debug "regex match: ${tan}YYYYMMDD${purple}"
# YYYYDDMM
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
$((10#${BASH_REMATCH[5]})) -gt 12 &&
$((10#${BASH_REMATCH[5]})) -lt 32 &&
$((10#${BASH_REMATCH[6]})) -lt 13 ]] \
$((10#${BASH_REMATCH[5]})) -gt 12 &&
$((10#${BASH_REMATCH[5]})) -lt 32 &&
$((10#${BASH_REMATCH[6]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[5]}))"
_parseDate_month="$((10#${BASH_REMATCH[6]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
debug "regex match: ${tan}YYYYMMDD${purple}"
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[6]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
debug "regex match: ${tan}YYYYMMDD${purple}"
# Assume YYYMMDD
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
$((10#${BASH_REMATCH[6]})) -lt 32 &&
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
$((10#${BASH_REMATCH[6]})) -lt 32 &&
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
; then
_parseDate_found="${BASH_REMATCH[2]}"
_parseDate_day="$((10#${BASH_REMATCH[6]}))"
_parseDate_month="$((10#${BASH_REMATCH[5]}))"
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
_parseDate_year="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
debug "regex match: ${tan}YYYYMMDD${purple}"
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
PARSE_DATE_DAY="$((10#${BASH_REMATCH[6]}))"
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[5]}))"
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
PARSE_DATE_YEAR="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
debug "regex match: ${tan}YYYYMMDD${purple}"
else
shopt -u nocasematch
return 1
fi
# # MMDD or DDYY
# elif [[ "$date" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then
# elif [[ "${_stringToTest}" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then
# debug "regex match: ${tan}MMDD or DDMM${purple}"
# _parseDate_found="${BASH_REMATCH[1]}"
# PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
# # Figure out if days are months or vice versa
# if [[ $(( 10#${BASH_REMATCH[2]} )) -gt 12 \
# && $(( 10#${BASH_REMATCH[2]} )) -lt 32 \
# && $(( 10#${BASH_REMATCH[3]} )) -lt 13 \
# ]]; then
# _parseDate_day="$(( 10#${BASH_REMATCH[2]} ))"
# _parseDate_month="$(( 10#${BASH_REMATCH[3]} ))"
# _parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
# _parseDate_year="$(date +%Y )"
# PARSE_DATE_DAY="$(( 10#${BASH_REMATCH[2]} ))"
# PARSE_DATE_MONTH="$(( 10#${BASH_REMATCH[3]} ))"
# PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
# PARSE_DATE_YEAR="$(date +%Y )"
# elif [[ $(( 10#${BASH_REMATCH[2]} )) -lt 13 \
# && $(( 10#${BASH_REMATCH[3]} )) -lt 32 \
# ]]; then
# _parseDate_day="$(( 10#${BASH_REMATCH[3]} ))"
# _parseDate_month="$(( 10#${BASH_REMATCH[2]} ))"
# _parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
# _parseDate_year="$(date +%Y )"
# PARSE_DATE_DAY="$(( 10#${BASH_REMATCH[3]} ))"
# PARSE_DATE_MONTH="$(( 10#${BASH_REMATCH[2]} ))"
# PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
# PARSE_DATE_YEAR="$(date +%Y )"
# else
# shopt -u nocasematch
# return 1
@@ -327,69 +468,102 @@ _parseDate_() {
else
shopt -u nocasematch
return 1
fi
[[ -z ${_parseDate_year:-} ]] && {
shopt -u nocasematch
return 1
[[ -z ${PARSE_DATE_YEAR:-} ]] && {
shopt -u nocasematch
return 1
}
((_parseDate_month >= 1 && _parseDate_month <= 12)) || {
shopt -u nocasematch
return 1
((PARSE_DATE_MONTH >= 1 && PARSE_DATE_MONTH <= 12)) || {
shopt -u nocasematch
return 1
}
((_parseDate_day >= 1 && _parseDate_day <= 31)) || {
shopt -u nocasematch
return 1
((PARSE_DATE_DAY >= 1 && PARSE_DATE_DAY <= 31)) || {
shopt -u nocasematch
return 1
}
debug "${tan}\$_parseDate_found: ${_parseDate_found}${purple}"
debug "${tan}\$_parseDate_year: ${_parseDate_year}${purple}"
debug "${tan}\$_parseDate_month: ${_parseDate_month}${purple}"
debug "${tan}\$_parseDate_monthName: ${_parseDate_monthName}${purple}"
debug "${tan}\$_parseDate_day: ${_parseDate_day}${purple}"
[[ -z ${_parseDate_hour:-} ]] || debug "${tan}\$_parseDate_hour: ${_parseDate_hour}${purple}"
[[ -z ${_parseDate_minute:-} ]] || debug "${tan}\$_parseDate_minute: ${_parseDate_minute}${purple}"
debug "${tan}\$PARSE_DATE_FOUND: ${PARSE_DATE_FOUND}${purple}"
debug "${tan}\$PARSE_DATE_YEAR: ${PARSE_DATE_YEAR}${purple}"
debug "${tan}\$PARSE_DATE_MONTH: ${PARSE_DATE_MONTH}${purple}"
debug "${tan}\$PARSE_DATE_MONTH_NAME: ${PARSE_DATE_MONTH_NAME}${purple}"
debug "${tan}\$PARSE_DATE_DAY: ${PARSE_DATE_DAY}${purple}"
[[ -z ${PARSE_DATE_HOUR:-} ]] || debug "${tan}\$PARSE_DATE_HOUR: ${PARSE_DATE_HOUR}${purple}"
[[ -z ${PARSE_DATE_MINUTE:-} ]] || debug "${tan}\$PARSE_DATE_MINUTE: ${PARSE_DATE_MINUTE}${purple}"
shopt -u nocasematch
# Output results for BATS tests
if [ "${automated_test_in_progress:-}" ]; then
echo "_parseDate_found: ${_parseDate_found}"
echo "_parseDate_year: ${_parseDate_year}"
echo "_parseDate_month: ${_parseDate_month}"
echo "_parseDate_monthName: ${_parseDate_monthName}"
echo "_parseDate_day: ${_parseDate_day}"
echo "_parseDate_hour: ${_parseDate_hour}"
echo "_parseDate_minute: ${_parseDate_minute}"
echo "PARSE_DATE_FOUND: ${PARSE_DATE_FOUND}"
echo "PARSE_DATE_YEAR: ${PARSE_DATE_YEAR}"
echo "PARSE_DATE_MONTH: ${PARSE_DATE_MONTH}"
echo "PARSE_DATE_MONTH_NAME: ${PARSE_DATE_MONTH_NAME}"
echo "PARSE_DATE_DAY: ${PARSE_DATE_DAY}"
echo "PARSE_DATE_HOUR: ${PARSE_DATE_HOUR}"
echo "PARSE_DATE_MINUTE: ${PARSE_DATE_MINUTE}"
fi
}
_formatDate_() {
# DESC: Reformats dates into user specified formats
# ARGS: $1 (Required) - Date to be formatted
# $2 (Optional) - Format in any format accepted by bash's date command. Examples listed below.
# %F - YYYY-MM-DD
# %D - MM/DD/YY
# %a - Name of weekday in short (like Sun, Mon, Tue, Wed, Thu, Fri, Sat)
# %A - Name of weekday in full (like Sunday, Monday, Tuesday)
# '+%m %d, %Y' - 12 27, 2019
# OUTS: Echo result to STDOUT
# USAGE: _formatDate_ "Jan 10, 2019" "%D"
# NOTE: Defaults to YYYY-MM-DD or $(date +%F)
_readableUnixTimestamp_() {
# DESC:
# Format unix timestamp to human readable format. If format string is not specified then
# default to "yyyy-mm-dd hh:mm:ss"
# ARGS:
# $1 (Required) - Unix timestamp to be formatted
# $2 (Optional) - Format string
# OUTS:
# 0 If successful
# 1 If failed to convert
# stdout: Human readable format of unix timestamp
# USAGE:
# _readableUnixTimestamp_ "1591554426"
# _readableUnixTimestamp_ "1591554426" "%Y-%m-%d"
# CREDIT:
# https://github.com/labbots/bash-utility/blob/master/src/date.sh
[[ $# -eq 0 ]] && {
error 'Missing required argument to _formatDate_()'
return 1
}
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _timestamp="${1}"
local _format="${2:-"%F %T"}"
local _out="$(date -d "@${_timestamp}" +"${_format}")" || return 1
printf "%s\n" "${_out}"
}
local d="${1}"
local format="${2:-%F}"
format="${format//+/}"
_toSeconds_() {
# DESC:
# Converts HH:MM:SS to seconds
# ARGS:
# $1 (Required) - Time in HH:MM:SS
# OUTS:
# stdout: Print seconds
# USAGE:
# _toSeconds_ "01:00:00"
# NOTE:
# Acceptable Input Formats
# 24 12 09
# 12,12,09
# 12;12;09
# 12:12:09
# 12-12-09
# 12H12M09S
# 12h12m09s
if command -v gdate >/dev/null 2>&1; then
gdate -d "${d}" "+${format}"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _saveIFS
local _h
local _m
local _s
if [[ $1 =~ [0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2} ]]; then
_saveIFS="${IFS}"
IFS=":,;-_, HhMmSs" read -r h m s <<<"$1"
IFS="${_saveIFS}"
else
date -d "${d}" "+${format}"
_h="$1"
_m="$2"
_s="$3"
fi
printf "%s\n" "$((10#$_h * 3600 + 10#$_m * 60 + 10#$_s))"
}

58
utilities/debug.bash Normal file
View File

@@ -0,0 +1,58 @@
# Functions to aid in debugging bash scripts
_pauseScript_() {
# DESC:
# Pause a script at any point and continue after user input
# ARGS:
# $1 (Optional) - String for customized message
local _pauseMessage
_pauseMessage="${1:-Paused. Ready to continue?}"
if _seekConfirmation_ "${_pauseMessage}"; then
info "Continuing..."
else
notice "Exiting Script"
_safeExit_
fi
}
_printAnsi_() {
# DESC:
# Helps debug ansi escape sequence in text by displaying the escape codes
# ARGS:
# $1 (Required) String input with ansi escape sequence.
# OUTS:
# stdout: Ansi escape sequence printed in output as is.
# USAGE:
# _printAnsi_ "$(tput bold)$(tput setaf 9)Some Text"
# CREDIT:
# https://github.com/labbots/bash-utility/blob/master/src/debug.sh
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
#echo $(tr -dc '[:print:]'<<<$1)
printf "%s\n" "${1//$'\e'/\\e}"
}
_printArray_() {
# DESC:
# Prints the content of array as key value pairs for easier debugging
# ARGS:
# $1 (Required) - String variable name of the array
# OUTS:
# stdout: Formatted key value of array.one
# USAGE:
# testArray=("1" "2" "3" "4")
# _printArray_ "testArray"
# CREDIT:
# https://github.com/labbots/bash-utility/blob/master/src/debug.sh
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare -n _arr="${1}"
for _k in "${!_arr[@]}"; do
printf "%s = %s\n" "$_k" "${_arr[$_k]}"
done
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,18 @@
# Functions for use on computers running MacOS
_haveScriptableFinder_() {
# DESC: Determine whether we can script the Finder or not
# ARGS: None
# OUTS: true/false
# DESC:
# Determine whether we can script the Finder or not
# ARGS:
# None
# OUTS:
# 0 if we can script the Finder
# 1 if not
local finder_pid
finder_pid="$(pgrep -f /System/Library/CoreServices/Finder.app | head -n 1)"
local _finder_pid
_finder_pid="$(pgrep -f /System/Library/CoreServices/Finder.app | head -n 1)"
if [[ (${finder_pid} -gt 1) && (${STY-} == "") ]]; then
if [[ (${_finder_pid} -gt 1) && (${STY-} == "") ]]; then
return 0
else
return 1
@@ -16,24 +20,56 @@ _haveScriptableFinder_() {
}
_guiInput_() {
# DESC: Ask for user input using a Mac dialog box
# ARGS: $1 (Optional) - Text in dialogue box (Default: Password)
# OUTS: None
# NOTE: https://github.com/herrbischoff/awesome-osx-command-line/blob/master/functions.md
# DESC:
# Ask for user input using a Mac dialog box
# ARGS:
# $1 (Optional) - Text in dialogue box (Default: Password)
# OUTS:
# MacOS dialog box output
# 1 if no output
# CREDIT
# https://github.com/herrbischoff/awesome-osx-command-line/blob/master/functions.md
if _haveScriptableFinder_; then
guiPrompt="${1:-Password:}"
guiInput=$(
osascript &>/dev/null <<EOF
local _guiPrompt="${1:-Password:}"
local _guiInput=$(
osascript &>/dev/null <<GUI_INPUT_MESSAGE
tell application "System Events"
activate
text returned of (display dialog "${guiPrompt}" default answer "" with hidden answer)
text returned of (display dialog "${_guiPrompt}" default answer "" with hidden answer)
end tell
EOF
GUI_INPUT_MESSAGE
)
echo -n "${guiInput}"
echo -n "${_guiInput}"
else
error "No GUI input without macOS"
return 1
fi
}
_useGNUutils_() {
# DESC:
# Add GNU utilities to PATH to allow consistent use of sed/grep/tar/etc. on MacOS
# ARGS:
# None
# OUTS:
# 0 if successful
# 1 if unsuccessful
# PATH: Adds GNU utilities to the path
# USAGE:
# # if ! _useGNUUtils_; then exit 1; fi
# NOTES:
# GNU utilities can be added to MacOS using Homebrew
[ ! "$(declare -f "_setPATH_")" ] && fatal "${FUNCNAME[0]} needs function _setPATH_"
if _setPATH_ \
"/usr/local/opt/gnu-tar/libexec/gnubin" \
"/usr/local/opt/coreutils/libexec/gnubin" \
"/usr/local/opt/gnu-sed/libexec/gnubin" \
"/usr/local/opt/grep/libexec/gnubin"; then
return 0
else
return 1
fi
}

482
utilities/misc.bash Normal file
View File

@@ -0,0 +1,482 @@
# Functions which provide base functionality for other scripts
_checkTerminalSize_() {
# DESC:
# Checks the size of the terminal window. Updates LINES/COLUMNS if necessary
# ARGS:
# NONE
# OUTS:
# NONE
# USAGE:
# _updateTerminalSize_
# CREDIT:
# https://github.com/labbots/bash-utility
shopt -s checkwinsize && (: && :)
trap 'shopt -s checkwinsize; (:;:)' SIGWINCH
}
_detectOS_() {
# DESC:
# Identify the OS the script is run on
# ARGS:
# None
# OUTS:
# 0 - Success
# 1 - Failed to detect OS
# stdout: One of 'mac', 'linux', 'windows'
# USAGE:
# _detectOS_
# CREDIT:
# https://github.com/labbots/bash-utility
local _uname
local _os
if _uname=$(command -v uname); then
case $("${_uname}" | tr '[:upper:]' '[:lower:]') in
linux*)
_os="linux"
;;
darwin*)
_os="mac"
;;
msys* | cygwin* | mingw* | nt | win*)
# or possible 'bash on windows'
_os="windows"
;;
*)
return 1
;;
esac
else
return 1
fi
printf "%s" "${_os}"
}
_detectLinuxDistro_() {
# DESC:
# Detects the Linux distribution of the host the script is run on
# ARGS:
# None
# OUTS:
# 0 - If Linux distro is successfully detected
# 1 - If unable to detect OS distro or not on Linux
# stdout: Prints name of Linux distro in lower case (ex: 'raspbian' or 'debian')
# USAGE:
# _detectLinuxDistro_
# CREDIT:
# https://github.com/labbots/bash-utility
local _distro
if [[ -f /etc/os-release ]]; then
# shellcheck disable=SC1091
. "/etc/os-release"
_distro="${NAME}"
elif type lsb_release >/dev/null 2>&1; then
# linuxbase.org
_distro=$(lsb_release -si)
elif [[ -f /etc/lsb-release ]]; then
# For some versions of Debian/Ubuntu without lsb_release command
# shellcheck disable=SC1091
. /etc/lsb-release
_distro="${DISTRIB_ID}"
elif [[ -f /etc/debian_version ]]; then
# Older Debian/Ubuntu/etc.
_distro="debian"
elif [[ -f /etc/SuSe-release ]]; then
# Older SuSE/etc.
_distro="suse"
elif [[ -f /etc/redhat-release ]]; then
# Older Red Hat, CentOS, etc.
_distro="redhat"
else
return 1
fi
printf "%s" "${_distro}" | tr '[:upper:]' '[:lower:]'
}
_detectMacOSVersion_() {
# DESC:
# Detects the host's version of MacOS
# ARGS:
# None
# OUTS:
# 0 - Success
# 1 - Can not find macOS version number or not on a mac
# stdout: Prints the version number of macOS (ex: 11.6.1)
# USAGE:
# _detectMacOSVersion_
# CREDIT:
# https://github.com/labbots/bash-utility
[ ! "$(declare -f "_detectOS_")" ] && fatal "${FUNCNAME[0]} needs function _detectOS_"
if [[ "$(_detectOS_)" == "mac" ]]; then
local _mac_version
_mac_version="$(sw_vers -productVersion)"
printf "%s" "${_mac_version}"
else
return 1
fi
}
_detectLinuxDistro_() {
# DESC:
# Detects the Linux distribution of the host the script is run on
# ARGS:
# None
# OUTS:
# 0 - If Linux distro is successfully detected
# 1 - If unable to detect OS distro or not on Linux
# stdout: Prints name of Linux distro in lower case (ex: 'raspbian' or 'debian')
# USAGE:
# _detectLinuxDistro_
# CREDIT:
# https://github.com/labbots/bash-utility
local _distro
if [[ -f /etc/os-release ]]; then
# shellcheck disable=SC1091
. "/etc/os-release"
_distro="${NAME}"
elif type lsb_release >/dev/null 2>&1; then
# linuxbase.org
_distro=$(lsb_release -si)
elif [[ -f /etc/lsb-release ]]; then
# For some versions of Debian/Ubuntu without lsb_release command
# shellcheck disable=SC1091
. /etc/lsb-release
_distro="${DISTRIB_ID}"
elif [[ -f /etc/debian_version ]]; then
# Older Debian/Ubuntu/etc.
_distro="debian"
elif [[ -f /etc/SuSe-release ]]; then
# Older SuSE/etc.
_distro="suse"
elif [[ -f /etc/redhat-release ]]; then
# Older Red Hat, CentOS, etc.
_distro="redhat"
else
return 1
fi
printf "%s" "${_distro}" | tr '[:upper:]' '[:lower:]'
}
_execute_() {
# DESC:
# Executes commands while respecting global DRYRUN, VERBOSE, LOGGING, and QUIET flags
# ARGS:
# $1 (Required) - The command to be executed. Quotation marks MUST be escaped.
# $2 (Optional) - String to display after command is executed
# OPTS:
# -v Always print output from the execute function to STDOUT
# -n Use NOTICE level alerting (default is INFO)
# -p Pass a failed command with 'return 0'. This effectively bypasses set -e.
# -e Bypass _alert_ functions and use 'echo RESULT'
# -s Use '_alert_ success' for successful output. (default is 'info')
# -q Do not print output (QUIET mode)
# OUTS:
# stdout: Configurable output
# USE :
# _execute_ "cp -R \"~/dir/somefile.txt\" \"someNewFile.txt\"" "Optional message"
# _execute_ -sv "mkdir \"some/dir\""
# NOTE:
# If $DRYRUN=true, no commands are executed and the command that would have been executed
# is printed to STDOUT using dryrun level alerting
# If $VERBOSE=true, the command's native output is printed to stdout. This can be forced
# with '_execute_ -v'
local _localVerbose=false
local _passFailures=false
local _echoResult=false
local _echoSuccessResult=false
local _quietMode=false
local _echoNoticeResult=false
local opt
local OPTIND=1
while getopts ":vVpPeEsSqQnN" opt; do
case $opt in
v | V) _localVerbose=true ;;
p | P) _passFailures=true ;;
e | E) _echoResult=true ;;
s | S) _echoSuccessResult=true ;;
q | Q) _quietMode=true ;;
n | N) _echoNoticeResult=true ;;
*)
{
error "Unrecognized option '$1' passed to _execute_. Exiting."
_safeExit_
}
;;
esac
done
shift $((OPTIND - 1))
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _command="${1}"
local _executeMessage="${2:-$1}"
local _saveVerbose=${VERBOSE}
if "${_localVerbose}"; then
VERBOSE=true
fi
if "${DRYRUN}"; then
if "${_quietMode}"; then
VERBOSE=${_saveVerbose}
return 0
fi
if [ -n "${2:-}" ]; then
dryrun "${1} (${2})" "$(caller)"
else
dryrun "${1}" "$(caller)"
fi
elif ${VERBOSE}; then
if eval "${_command}"; then
if "${_quietMode}"; then
VERBOSE=${_saveVerbose}
elif "${_echoResult}"; then
printf "%s\n" "${_executeMessage}"
elif "${_echoSuccessResult}"; then
success "${_executeMessage}"
elif "${_echoNoticeResult}"; then
notice "${_executeMessage}"
else
info "${_executeMessage}"
fi
else
if "${_quietMode}"; then
VERBOSE=${_saveVerbose}
elif "${_echoResult}"; then
printf "%s\n" "warning: ${_executeMessage}"
else
warning "${_executeMessage}"
fi
VERBOSE=${_saveVerbose}
"${_passFailures}" && return 0 || return 1
fi
else
if eval "${_command}" >/dev/null 2>&1; then
if "${_quietMode}"; then
VERBOSE=${_saveVerbose}
elif "${_echoResult}"; then
printf "%s\n" "${_executeMessage}"
elif "${_echoSuccessResult}"; then
success "${_executeMessage}"
elif "${_echoNoticeResult}"; then
notice "${_executeMessage}"
else
info "${_executeMessage}"
fi
else
if "${_quietMode}"; then
VERBOSE=$_saveVerbose
elif "${_echoResult}"; then
printf "%s\n" "error: ${_executeMessage}"
else
warning "${_executeMessage}"
fi
VERBOSE=${_saveVerbose}
"${_passFailures}" && return 0 || return 1
fi
fi
VERBOSE=${_saveVerbose}
return 0
}
_findBaseDir_() {
# DESC:
# Locates the real directory of the script being run. Similar to GNU readlink -n
# ARGS:
# None
# OUTS:
# stdout: prints result
# USAGE:
# baseDir="$(_findBaseDir_)"
# cp "$(_findBaseDir_ "somefile.txt")" "other_file.txt"
local _source
local _dir
# Is file sourced?
[[ $_ != "$0" ]] \
&& _source="${BASH_SOURCE[1]}" \
|| _source="${BASH_SOURCE[0]}"
while [ -h "${_source}" ]; do # Resolve $SOURCE until the file is no longer a symlink
_dir="$(cd -P "$(dirname "${_source}")" && pwd)"
_source="$(readlink "${_source}")"
[[ ${_source} != /* ]] && _source="${_dir}/${_source}" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
printf "%s/n" "$(cd -P "$(dirname "${_source}")" && pwd)"
}
_generateUUID_() {
# DESC:
# Generates a UUID
# ARGS:
# None
# OUTS:
# 0 - Success
# 1 - Failure
# stdout: UUID
# USAGE:
# _generateUUID_
# CREDIT:
# https://github.com/labbots/bash-utility
local _c
local n
local _b
_c="89ab"
for ((n = 0; n < 16; ++n)); do
_b="$((RANDOM % 256))"
case "$n" in
6) printf '4%x' "$((_b % 16))" ;;
8) printf '%c%x' "${_c:$RANDOM%${#_c}:1}" "$((_b % 16))" ;;
3 | 5 | 7 | 9)
printf '%02x-' "${_b}"
;;
*)
printf '%02x' "${_b}"
;;
esac
done
printf '\n'
}
_makeProgressBar_() {
# DESC:
# Prints a progress bar within a for/while loop
# ARGS:
# $1 (Required) - The total number of items counted
# $2 (Optional) - The optional title of the progress bar
# OUTS: stdout: progress bar
# USAGE:
# for number in $(seq 0 100); do
# sleep 1
# _makeProgressBar_ "100" "Counting numbers"
# done
[[ $# == 0 ]] && return # Do nothing if no arguments are passed
(${QUIET}) && return
(${VERBOSE}) && return
[ ! -t 1 ] && return # Do nothing if the output is not a terminal
[ ${1} == 1 ] && return # Do nothing with a single element
local n="${1}"
local _width=30
local _barCharacter="#"
local _percentage
local _num
local _bar
local _progressBarLine
local _barTitle="${2:-Running Process}"
local n
((n = n - 1))
# Reset the count
[ -z "${progressBarProgress:-}" ] && progressBarProgress=0
tput civis # Hide the cursor
trap 'tput cnorm; exit 1' SIGINT
if [ ! "${progressBarProgress}" -eq $n ]; then
#echo "progressBarProgress: $progressBarProgress"
# Compute the percentage.
_percentage=$((progressBarProgress * 100 / $1))
# Compute the number of blocks to represent the percentage.
_num=$((progressBarProgress * _width / $1))
# Create the progress bar string.
_bar=""
if [ ${_num} -gt 0 ]; then
_bar=$(printf "%0.s${_barCharacter}" $(seq 1 ${_num}))
fi
# Print the progress bar.
_progressBarLine=$(printf "%s [%-${_width}s] (%d%%)" " ${_barTitle}" "${_bar}" "${_percentage}")
printf "%s\r" "${_progressBarLine}"
# echo -ne "${_progressBarLine}\r"
progressBarProgress=$((progressBarProgress + 1))
else
# Clear the progress bar when complete
# echo -ne "\033[0K\r"
tput el # Clear the line
unset progressBarProgress
fi
tput cnorm
}
_runAsRoot_() {
# DESC:
# Run the requested command as root (via sudo if requested)
# ARGS:
# $1 (optional): Set to zero to not attempt execution via sudo
# $@ (required): Passed through for execution as root user
# OUTS:
# Runs the requested command as root
# CREDIT:
# https://github.com/ralish/bash-script-template
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _skip_sudo=false
if [[ ${1} =~ ^0$ ]]; then
_skip_sudo=true
shift
fi
if [[ ${EUID} -eq 0 ]]; then
"$@"
elif [[ -z ${_skip_sudo} ]]; then
sudo -H -- "$@"
else
fatal "Unable to run requested command as root: $*"
fi
}
_seekConfirmation_() {
# DESC:
# Seek user input for yes/no question
# ARGS:
# $1 (Required) - Question being asked
# OUTS:
# 0 if answer is "yes"
# 1 if answer is "no"
# USAGE:
# _seekConfirmation_ "Do something?" && echo "okay" || echo "not okay"
# OR
# if _seekConfirmation_ "Answer this question"; then
# something
# fi
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _yesNo
input "${1}"
if "${FORCE}"; then
debug "Forcing confirmation with '--force' flag set"
echo -e ""
return 0
else
while true; do
read -r -p " (y/n) " _yesNo
case ${_yesNo} in
[Yy]*) return 0 ;;
[Nn]*) return 1 ;;
*) input "Please answer yes or no." ;;
esac
done
fi
}

View File

@@ -1,73 +0,0 @@
_fromSeconds_() {
# DESC: Convert seconds to HH:MM:SS
# ARGS: $1 (Required) - Time in seconds
# OUTS: Print HH:MM:SS to STDOUT
# USAGE: _convertSecs_ "SECONDS"
# To compute the time it takes a script to run:
# STARTTIME=$(date +"%s")
# ENDTIME=$(date +"%s")
# TOTALTIME=$(($ENDTIME-$STARTTIME)) # human readable time
# _convertSecs_ "$TOTALTIME"
((h = ${1} / 3600))
((m = (${1} % 3600) / 60))
((s = ${1} % 60))
printf "%02d:%02d:%02d\n" $h $m $s
}
_toSeconds_() {
# DESC: Converts HH:MM:SS to seconds
# ARGS: $1 (Required) - Time in HH:MM:SS
# OUTS: Print seconds to STDOUT
# USAGE: _toSeconds_ "01:00:00"
# NOTE: Acceptable Input Formats
# 24 12 09
# 12,12,09
# 12;12;09
# 12:12:09
# 12-12-09
# 12H12M09S
# 12h12m09s
local saveIFS
local h
local m
local s
if [[ $1 =~ [0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2} ]]; then
saveIFS="$IFS"
IFS=":,;-_, HhMmSs" read -r h m s <<<"$1"
IFS="$saveIFS"
else
h="$1"
m="$2"
s="$3"
fi
echo $((10#$h * 3600 + 10#$m * 60 + 10#$s))
}
_countdown_() {
# DESC: Sleep for a specified amount of time
# ARGS: $1 (Optional) - Total seconds to sleep for(Default is 10)
# $2 (Optional) - Increment to count down
# $3 (Optional) - Message to print at each increment (default is ...)
# OUTS: None
# USAGE: _countdown_ 10 1 "Waiting for cache to invalidate"
local i ii t
local n=${1:-10}
local stime=${2:-1}
local message="${3:-...}"
((t = n + 1))
for ((i = 1; i <= n; i++)); do
((ii = t - i))
if declare -f "info" &>/dev/null 2>&1; then
info "${message} ${ii}"
else
echo "${message} ${ii}"
fi
sleep $stime
done
}

View File

@@ -1,148 +1,136 @@
_haveInternet_() {
# DESC: Tests to see if there is an active Internet connection
# ARGS: None
# OUTS: None
# USAGE: _haveInternet_ && [SOMETHING]
# NOTE: https://stackoverflow.com/questions/929368/
if command -v fping &>/dev/null; then
fping 1.1.1.1 &>/dev/null \
&& return 0 \
|| return 1
elif ping -t 2 -c 1 1 1.1.1.1 &>/dev/null; then
return 0
elif command -v route &>/dev/null; then
local GATEWAY="$(route -n get default | grep gateway)"
ping -t 2 -c 1 "$(echo "${GATEWAY}" | cut -d ':' -f 2)" &>/dev/null \
&& return 0 \
|| return 1
elif command -v ip &>/dev/null; then
ping -t 2 -c 1 "$(ip r | grep default | cut -d ' ' -f 3)" &>/dev/null \
&& return 0 \
|| return 1
else
return 1
fi
}
# Functions for working with network services
_httpStatus_() {
# DESC: Report the HTTP status of a specified URL
# ARGS: $1 (Required) - URL (will work fine without https:// prefix)
# DESC:
# Report the HTTP status of a specified URL
# ARGS:
# $1 (Required) - URL (will work fine without https:// prefix)
# $2 (Optional) - Seconds to wait until timeout (Default is 3)
# $3 (Optional) - either '--code' or '--status' (default)
# $4 (optional) - CURL opts separated by spaces (Use -L to follow redirects)
# OUTS: Prints output to STDOUT
# USAGE: _httpStatus_ URL [timeout] [--code or --status] [curl opts]
# NOTE: https://gist.github.com/rsvp/1171304
# OUTS:
# stdout: Prints the HTTP status code or status message
# USAGE:
# _httpStatus_ URL [timeout] [--code or --status] [curl opts]
# NOTE:
# https://gist.github.com/rsvp/1171304
# EXAMPLES
# $ _httpStatus_ bit.ly
# 301 Redirection: Moved Permanently
#
# Example: $ _httpStatus_ bit.ly
# 301 Redirection: Moved Permanently
#
# Example: $ _httpStatus_ www.google.com 100 --code
local code
local status
# $ _httpStatus_ www.google.com 100 --code
local saveIFS=${IFS}
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _saveIFS=${IFS}
IFS=$' \n\t'
local url=${1:?_httpStatus_ needs an url}
local timeout=${2:-'3'}
local flag=${3:-'--status'}
local arg4=${4:-''}
local arg5=${5:-''}
local arg6=${6:-''}
local arg7=${7:-''}
local curlops="${arg4} ${arg5} ${arg6} ${arg7}"
local _url=${1}
local _timeout=${2:-3}
local _flag=${3:---status}
local _arg4=${4:-}
local _arg5=${5:-}
local _arg6=${6:-}
local _arg7=${7:-}
local _curlops="${_arg4} ${_arg5} ${_arg6} ${_arg7}"
local _code
local _status
# __________ get the CODE which is numeric:
code=$(echo "$(curl --write-out %{http_code} --silent --connect-timeout "${timeout}" \
--no-keepalive "${curlops}" --output /dev/null "${url}")")
_code=$(curl --write-out %{http_code} --silent --connect-timeout "${_timeout}" \
--no-keepalive ${_curlops} --output /dev/null ${_url})
# __________ get the STATUS (from code) which is human interpretable:
case $code in
000) status="Not responding within ${timeout} seconds" ;;
100) status="Informational: Continue" ;;
101) status="Informational: Switching Protocols" ;;
200) status="Successful: OK within ${timeout} seconds" ;;
201) status="Successful: Created" ;;
202) status="Successful: Accepted" ;;
203) status="Successful: Non-Authoritative Information" ;;
204) status="Successful: No Content" ;;
205) status="Successful: Reset Content" ;;
206) status="Successful: Partial Content" ;;
300) status="Redirection: Multiple Choices" ;;
301) status="Redirection: Moved Permanently" ;;
302) status="Redirection: Found residing temporarily under different URI" ;;
303) status="Redirection: See Other" ;;
304) status="Redirection: Not Modified" ;;
305) status="Redirection: Use Proxy" ;;
306) status="Redirection: status not defined" ;;
307) status="Redirection: Temporary Redirect" ;;
400) status="Client Error: Bad Request" ;;
401) status="Client Error: Unauthorized" ;;
402) status="Client Error: Payment Required" ;;
403) status="Client Error: Forbidden" ;;
404) status="Client Error: Not Found" ;;
405) status="Client Error: Method Not Allowed" ;;
406) status="Client Error: Not Acceptable" ;;
407) status="Client Error: Proxy Authentication Required" ;;
408) status="Client Error: Request Timeout within ${timeout} seconds" ;;
409) status="Client Error: Conflict" ;;
410) status="Client Error: Gone" ;;
411) status="Client Error: Length Required" ;;
412) status="Client Error: Precondition Failed" ;;
413) status="Client Error: Request Entity Too Large" ;;
414) status="Client Error: Request-URI Too Long" ;;
415) status="Client Error: Unsupported Media Type" ;;
416) status="Client Error: Requested Range Not Satisfiable" ;;
417) status="Client Error: Expectation Failed" ;;
500) status="Server Error: Internal Server Error" ;;
501) status="Server Error: Not Implemented" ;;
502) status="Server Error: Bad Gateway" ;;
503) status="Server Error: Service Unavailable" ;;
504) status="Server Error: Gateway Timeout within ${timeout} seconds" ;;
505) status="Server Error: HTTP Version Not Supported" ;;
*) die "httpstatus: status not defined." ;;
case $_code in
000) _status="Not responding within ${_timeout} seconds" ;;
100) _status="Informational: Continue" ;;
101) _status="Informational: Switching Protocols" ;;
200) _status="Successful: OK within ${_timeout} seconds" ;;
201) _status="Successful: Created" ;;
202) _status="Successful: Accepted" ;;
203) _status="Successful: Non-Authoritative Information" ;;
204) _status="Successful: No Content" ;;
205) _status="Successful: Reset Content" ;;
206) _status="Successful: Partial Content" ;;
300) _status="Redirection: Multiple Choices" ;;
301) _status="Redirection: Moved Permanently" ;;
302) _status="Redirection: Found residing temporarily under different URI" ;;
303) _status="Redirection: See Other" ;;
304) _status="Redirection: Not Modified" ;;
305) _status="Redirection: Use Proxy" ;;
306) _status="Redirection: status not defined" ;;
307) _status="Redirection: Temporary Redirect" ;;
400) _status="Client Error: Bad Request" ;;
401) _status="Client Error: Unauthorized" ;;
402) _status="Client Error: Payment Required" ;;
403) _status="Client Error: Forbidden" ;;
404) _status="Client Error: Not Found" ;;
405) _status="Client Error: Method Not Allowed" ;;
406) _status="Client Error: Not Acceptable" ;;
407) _status="Client Error: Proxy Authentication Required" ;;
408) _status="Client Error: Request Timeout within ${_timeout} seconds" ;;
409) _status="Client Error: Conflict" ;;
410) _status="Client Error: Gone" ;;
411) _status="Client Error: Length Required" ;;
412) _status="Client Error: Precondition Failed" ;;
413) _status="Client Error: Request Entity Too Large" ;;
414) _status="Client Error: Request-URI Too Long" ;;
415) _status="Client Error: Unsupported Media Type" ;;
416) _status="Client Error: Requested Range Not Satisfiable" ;;
417) _status="Client Error: Expectation Failed" ;;
500) _status="Server Error: Internal Server Error" ;;
501) _status="Server Error: Not Implemented" ;;
502) _status="Server Error: Bad Gateway" ;;
503) _status="Server Error: Service Unavailable" ;;
504) _status="Server Error: Gateway Timeout within ${_timeout} seconds" ;;
505) _status="Server Error: HTTP Version Not Supported" ;;
*) fatal "httpstatus: status not defined." ;;
esac
case ${flag} in
--status) echo "${code} ${status}" ;;
-s) echo "${code} ${status}" ;;
--code) echo "${code}" ;;
-c) echo "${code}" ;;
*) echo " httpstatus: bad flag" && _safeExit_ ;;
case ${_flag} in
--status) echo "${_code} ${_status}" ;;
-s) echo "${_code} ${_status}" ;;
--code) echo "${_code}" ;;
-c) echo "${_code}" ;;
*) echo " _httpStatus_: bad flag" && _safeExit_ ;;
esac
IFS="${saveIFS}"
IFS="${_saveIFS}"
}
_pushover_() {
# DESC: Sends a notification via Pushover
# ARGS: $1 (Required) - Title of notification
# DESC:
# Sends a notification via Pushover
# ARGS:
# $1 (Required) - Title of notification
# $2 (Required) - Body of notification
# OUTS: None
# $3 (Required) - User Token
# $4 (Required) - API Key
# $5 (Optional) - Device
# OUTS:
# 0 if success
# 1 if failure
# USAGE: _pushover_ "Title Goes Here" "Message Goes Here"
# NOTE: The variables for the two API Keys must have valid values
# Credit: http://ryonsherman.blogspot.com/2012/10/shell-script-to-send-pushover.html
local PUSHOVERURL
local API_KEY
local USER_KEY
local DEVICE
local TITLE
local MESSAGE
[[ $# -lt 4 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
PUSHOVERURL="https://api.pushover.net/1/messages.json"
API_KEY="${PUSHOVER_API_KEY}"
USER_KEY="${PUSHOVER_USER_KEY}"
DEVICE=""
TITLE="${1}"
MESSAGE="${2}"
curl \
-F "token=${API_KEY}" \
-F "user=${USER_KEY}" \
-F "device=${DEVICE}" \
-F "title=${TITLE}" \
-F "message=${MESSAGE}" \
"${PUSHOVERURL}" >/dev/null 2>&1
local _pushoverURL="https://api.pushover.net/1/messages.json"
local _message="${2}"
local _apiKey="${3}"
local _userKey="${4}"
local _device="${5:-}"
if curl \
-F "token=${_apiKey}" \
-F "user=${_userKey}" \
-F "device=${_device}" \
-F "title=${_messageTitle}" \
-F "message=${_message}" \
"${_pushoverURL}" >/dev/null 2>&1; then
return 0
else
return 1
fi
}

438
utilities/strings.bash Normal file
View File

@@ -0,0 +1,438 @@
# Transform text using these functions
# Some were adapted from https://github.com/jmcantrell/bashful
_cleanString_() {
# DESC:
# Cleans a string of text
# ARGS:
# $1 (Required) - String to be cleaned
# $2 (optional) - Specific characters to be removed (separated by commas,
# escape regex special chars)
# OPTS:
# -l: Forces all text to lowercase
# -u: Forces all text to uppercase
# -a: Removes all non-alphanumeric characters except for spaces and dashes
# -p: Replace one character with another (separated by commas) (escape regex characters)
# -s: In combination with -a, replaces characters with a space
# OUTS:
# stdout: Prints cleaned string
# USAGE:
# _cleanString_ [OPT] [STRING] [CHARS TO REMOVE]
# _cleanString_ -lp " ,-" [STRING] [CHARS TO REMOVE]
# NOTES:
# Always cleaned:
# - leading white space
# - trailing white space
# - multiple spaces become a single space
# - remove spaces before and after -_
local opt
local _lc=false
local _uc=false
local _alphanumeric=false
local _replace=false
local _us=false
local OPTIND=1
while getopts ":lLuUaAsSpP" opt; do
case $opt in
l | L) _lc=true ;;
u | U) _uc=true ;;
a | A) _alphanumeric=true ;;
s | S) _us=true ;;
p | P)
shift
declare -a _pairs=()
IFS=',' read -r -a _pairs <<<"$1"
_replace=true
;;
*)
{
error "Unrecognized option '$1' passed to _execute. Exiting."
return 1
}
;;
esac
done
shift $((OPTIND - 1))
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _string="${1}"
local _userChars="${2:-}"
declare -a _arrayToClean=()
IFS=',' read -r -a _arrayToClean <<<"${_userChars}"
# trim trailing/leading white space and duplicate spaces/tabs
_string="$(echo "${_string}" | awk '{$1=$1};1')"
local i
for i in "${_arrayToClean[@]}"; do
debug "cleaning: $i"
_string="$(echo "${_string}" | sed "s/$i//g")"
done
("${_lc}") \
&& _string="$(echo "${_string}" | tr '[:upper:]' '[:lower:]')"
("${_uc}") \
&& _string="$(echo "${_string}" | tr '[:lower:]' '[:upper:]')"
if "${_alphanumeric}" && "${_us}"; then
_string="$(echo "${_string}" | tr -c '[:alnum:]_ -' ' ')"
elif "${_alphanumeric}"; then
_string="$(echo "${_string}" | sed "s/[^a-zA-Z0-9_ \-]//g")"
fi
if "${_replace}"; then
_string="$(echo "${_string}" | sed -E "s/${_pairs[0]}/${_pairs[1]}/g")"
fi
# trim trailing/leading white space and duplicate dashes
_string="$(echo "${_string}" | tr -s '-' | tr -s '_')"
_string="$(echo "${_string}" | sed -E 's/([_\-]) /\1/g' | sed -E 's/ ([_\-])/\1/g')"
_string="$(echo "${_string}" | awk '{$1=$1};1')"
echo "${_string}"
}
_decodeHTML_() {
# DESC:
# Decode HTML characters with sed. Utilizes a sed file for speed.
# ARGS:
# $1 (Required) - String to be decoded
# OUTS:
# 0 - Success
# 1 - Error
# stdout: Prints decoded output
# USAGE:
# _decodeHTML_ <string>
# NOTE:
# Must have a sed file containing replacements. See: ../sedfiles/htmlDecode.sed
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _sedFile
_sedFile="${HOME}/.sed/htmlDecode.sed"
[ -f "${_sedFile}" ] \
&& { printf "%s\n" "${1}" | sed -f "${_sedFile}"; } \
|| return 1
}
_decodeURL_() {
# DESC:
# Decode a URL encoded string
# ARGS:
# $1 (Required) - String to be decoded
# OUTS:
# Prints output to STDOUT
# USAGE:
# _decodeURL_ <string>
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _url_encoded="${1//+/ }"
printf '%b' "${_url_encoded//%/\\x}"
}
_encodeHTML_() {
# DESC:
# Encode HTML characters with sed
# ARGS:
# $1 (Required) - String to be encoded
# OUTS:
# 0 - Success
# 1 - Error
# stdout: Prints encoded output
# USAGE:
# _encodeHTML_ <string>
# NOTE:
# Must have a sed file containing replacements. See: ../sedfiles/htmlEncode.sed
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _sedFile
_sedFile="${HOME}/.sed/htmlEncode.sed"
[ -f "${_sedFile}" ] \
&& { echo "${1}" | sed -f "${_sedFile}"; } \
|| return 1
}
_encodeURL_() {
# DESC:
# URL encode a string
# ARGS:
# $1 (Required) - String to be encoded
# OUTS:
# Prints output to STDOUT
# USAGE:
# _encodeURL_ <string>
# CREDIT:
# https://gist.github.com/cdown/1163649
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local LANG=C
local i
for ((i = 0; i < ${#1}; i++)); do
if [[ ${1:i:1} =~ ^[a-zA-Z0-9\.\~_-]$ ]]; then
printf "${1:i:1}"
else
printf '%%%02X' "'${1:i:1}"
fi
done
}
_escapeString_() {
# DESC:
# Escapes a string by adding \ before special chars
# ARGS:
# $@ (Required) - String to be escaped
# OUTS:
# stdout: Prints escaped output
# USAGE:
# _escapeString_ "Some text here"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
printf "%s\n" "${@}" | sed 's/[]\.|$[ (){}?+*^]/\\&/g'
}
_lower_() {
# DESC:
# Convert a string to lowercase. Used through a pipe or here string.
# ARGS:
# None
# OUTS:
# None
# USAGE:
# text=$(_lower_ <<<"$1")
# echo "STRING" | _lower_
tr '[:upper:]' '[:lower:]'
}
_ltrim_() {
# DESC:
# Removes all leading whitespace (from the left). Used through a pipe or here string.
# ARGS:
# $1 (Optional) - Character to trim. Defaults to [:space:]
# OUTS:
# None
# USAGE:
# text=$(_ltrim_ <<<"$1")
# echo "STRING" | _ltrim_
local _char=${1:-[:space:]}
sed "s%^[${_char//%/\\%}]*%%"
}
_regexCapture_() {
# DESC:
# Use regex to validate and parse strings
# ARGS:
# $1 (Required) - Input String
# $2 (Required) - Regex pattern
# OUTS:
# 0 - Regex matched
# 1 - Regex did not match
# stdout: Prints string matching regex
# USAGE:
# _regex_ "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
# NOTE:
# This example only prints the first matching group. When using multiple capture
# groups some modification is needed.
# CREDIT:
# https://github.com/dylanaraps/pure-bash-bible
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
if [[ $1 =~ $2 ]]; then
printf '%s\n' "${BASH_REMATCH[1]}"
return 0
else
return 1
fi
}
_rtrim_() {
# DESC:
# Removes all leading whitespace (from the right). Used through a pipe or here string.
# ARGS:
# $1 (Optional) - Character to trim. Defaults to [:space:]
# OUTS:
# None
# USAGE:
# text=$(_rtrim_ <<<"$1")
# echo "STRING" | _rtrim_
local _char=${1:-[:space:]}
sed "s%[${_char//%/\\%}]*$%%"
}
_splitString_() {
# DESC:
# Splat a string into an array based on a given delimiter
# ARGS:
# $1 (Required) - String to be split
# $2 (Required) - Delimiter
# OUTS:
# 0 - Success
# 1 - Failure
# stdout: Values split by delimiter separated by newline
# USAGE:
# ARRAY=( $(_splitString_ "string1,string2,string3" ",") )
# CREDIT:
# https://github.com/labbots/bash-utility/blob/master/src/misc.sh
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
declare -a _arr=()
IFS=$'\n' read -d "" -ra _arr <<<"${1//$2/$'\n'}"
printf '%s\n' "${_arr[@]}"
}
_stringContains_() {
# DESC:
# Tests whether a string contains a substring
# ARGS:
# $1 (Required) - String to be tested
# $2 (Required) - Substring to be tested for
# OUTS:
# 0 - Search pattern found
# 1 - Pattern not found
# USAGE:
# _stringContains_ "Hello World!" "lo"
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
if [[ ${1} == *${2}* ]]; then
return 0
else
return 1
fi
}
_stringRegex_() {
# DESC:
# Tests whether a string matches a regex pattern
# ARGS:
# $1 (Required) - String to be tested
# $2 (Required) - Regex pattern to be tested for
# OUTS:
# 0 - Search pattern found
# 1 - Pattern not found
# USAGE:
# _stringContains_ "HELLO" "^[A-Z]*$"
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
if [[ ${1} =~ ${2} ]]; then
return 0
else
return 1
fi
}
_stripStopwords_() {
# DESC:
# Removes common stopwords from a string using a list of sed replacements located
# in an external file. Additional stopwords can be added in arg2
# ARGS:
# $1 (Required) - String to parse
# $2 (Optional) - Additional stopwords (comma separated)
# OUTS:
# 0 - Success
# 1 - Error
# stdout: Prints string cleaned of stopwords
# USAGE:
# CLEAN_WORD="$(_stripStopwords_ "[STRING]" "[MORE,STOP,WORDS]")"
# NOTE:
# Must have a sed file containing replacements. See: ../sedfiles/stopwords.sed
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
if ! sed --version | grep GNU &>/dev/null; then
fatal "_stripStopwords_: Required GNU sed not found. Exiting."
fi
local _string="${1}"
local _sedFile="${HOME}/.sed/stopwords.sed"
local _w
if [ -f "${_sedFile}" ]; then
_string="$(echo "${_string}" | sed -f "${_sedFile}")"
else
fatal "_stripStopwords_: Missing sedfile expected at: ${_sedFile}"
fi
declare -a _localStopWords=()
IFS=',' read -r -a _localStopWords <<<"${2:-}"
if [[ ${#_localStopWords[@]} -gt 0 ]]; then
for _w in "${_localStopWords[@]}"; do
_string="$(echo "${_string}" | sed -E "s/\b${_w}\b//gI")"
done
fi
# Remove double spaces and trim left/right
_string="$(echo "${_string}" | sed -E 's/[ ]{2,}/ /g' | _trim_)"
printf "%s\n" "${_string}"
}
_stripANSI_() {
# DESC:
# Strips ANSI escape sequences from a string
# ARGS:
# $1 (Required) - String to be cleaned
# OUTS:
# 0 - Success
# 1 - Failure
# stdout: Prints string with ANSI escape sequences removed
# USAGE:
# _stripANSI_ "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text.\e(B\e[m"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _tmp
local _esc
local _tpa
local _re
_tmp="${1}"
_esc=$(printf "\x1b")
_tpa=$(printf "\x28")
_re="(.*)${_esc}[\[${_tpa}][0-9]*;*[mKB](.*)"
while [[ ${_tmp} =~ ${_re} ]]; do
_tmp="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
done
printf "%s" "${_tmp}"
}
_trim_() {
# DESC:
# Removes all leading/trailing whitespace. Used through a pipe or here string.
# ARGS:
# None
# OUTS:
# None
# USAGE:
# text=$(_trim_ <<<"$1")
# echo "STRING" | _trim_
awk '{$1=$1;print}'
}
_upper_() {
# DESC:
# Convert a string to uppercase. Used through a pipe or here string.
# ARGS:
# None
# OUTS:
# None
# USAGE:
# text=$(_upper_ <<<"$1")
# echo "STRING" | _upper_
tr '[:lower:]' '[:upper:]'
}

View File

@@ -0,0 +1,119 @@
# Functions required to allow the script template and alert functions to be used
_acquireScriptLock_() {
# DESC:
# Acquire script lock to prevent running the same script a second time before the
# first instance exits
# ARGS:
# $1 (optional) - Scope of script execution lock (system or user)
# OUTS:
# exports $SCRIPT_LOCK - Path to the directory indicating we have the script lock
# Exits script if lock cannot be acquired
# NOTE:
# If the lock was acquired it's automatically released in _safeExit_()
local _lockDir
if [[ ${1:-} == 'system' ]]; then
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
else
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
fi
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
readonly SCRIPT_LOCK="${_lockDir}"
debug "Acquired script lock: ${tan}${SCRIPT_LOCK}${purple}"
else
if [ "$(declare -f "_safeExit_")" ]; then
error "Unable to acquire script lock: ${yellow}${LOCK_DIR}${red}"
fatal "If you trust the script isn't running, delete the lock dir"
else
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${LOCK_DIR}"
exit 1
fi
fi
}
_makeTempDir_() {
# DESC:
# Creates a temp directory to house temporary files
# ARGS:
# $1 (Optional) - First characters/word of directory name
# OUTS:
# Sets $TMP_DIR variable to the path of the temp directory
# USAGE:
# _makeTempDir_ "$(basename "$0")"
[ -d "${TMP_DIR:-}" ] && return 0
if [ -n "${1:-}" ]; then
TMP_DIR="${TMPDIR:-/tmp/}${1}.${RANDOM}.${RANDOM}.$$"
else
TMP_DIR="${TMPDIR:-/tmp/}$(basename "$0").${RANDOM}.${RANDOM}.${RANDOM}.$$"
fi
(umask 077 && mkdir "${TMP_DIR}") || {
fatal "Could not create temporary directory! Exiting."
}
debug "\$TMP_DIR=${TMP_DIR}"
}
_safeExit_() {
# DESC:
# Cleanup and exit from a script
# ARGS:
# $1 (optional) - Exit code (defaults to 0)
# OUTS:
# None
if [[ -d ${SCRIPT_LOCK:-} ]]; then
if command rm -rf "${SCRIPT_LOCK}"; then
debug "Removing script lock"
else
warning "Script lock could not be removed. Try manually deleting ${yellow}'${LOCK_DIR}'"
fi
fi
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
command rm -r "${TMP_DIR}"
else
command rm -r "${TMP_DIR}"
debug "Removing temp directory"
fi
fi
trap - INT TERM EXIT
exit ${1:-0}
}
_setPATH_() {
# DESC:
# Add directories to $PATH so script can find executables
# ARGS:
# $@ - One or more paths
# OUTS: Adds items to $PATH
# USAGE:
# _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
local _newPath
for _newPath in "$@"; do
if [ -d "${_newPath}" ]; then
if ! echo "${PATH}" | grep -Eq "(^|:)${_newPath}($|:)"; then
if PATH="${_newPath}:${PATH}"; then
debug "Added '${_newPath}' to PATH"
else
return 1
fi
else
debug "_setPATH_: '${_newPath}' already exists in PATH"
fi
else
debug "_setPATH_: can not find: ${_newPath}"
return 1
fi
done
return 0
}

View File

@@ -1,294 +0,0 @@
# Transform text using these functions
# Some were adapted from https://github.com/jmcantrell/bashful
_cleanString_() {
# DESC: Cleans a string of text
# ARGS: $1 (Required) - String to be cleaned
# $2 (optional) - Specific characters to be removed (separated by commas,
# escape regex special chars)
# OPTS: -l Forces all text to lowercase
# -u Forces all text to uppercase
# -a Removes all non-alphanumeric characters except for spaces and dashes
# -p Replace one character with another (separated by commas) (escape regex characters)
# -s In combination with -a, replaces characters with a space
# OUTS: Prints result to STDOUT
# USAGE: _cleanString_ [OPT] [STRING] [CHARS TO REMOVE]
# _cleanString_ -lp " ,-" [STRING] [CHARS TO REMOVE]
# NOTES: Always cleaned:
# - leading white space
# - trailing white space
# - multiple spaces become a single space
# - remove spaces before and after -_
local opt
local lc=false
local uc=false
local alphanumeric=false
local replace=false
local us=false
local OPTIND=1
while getopts ":lLuUaAsSpP" opt; do
case $opt in
l | L) lc=true ;;
u | U) uc=true ;;
a | A) alphanumeric=true ;;
s | S) us=true ;;
p | P)
shift
local pairs=()
IFS=',' read -r -a pairs <<<"$1"
replace=true
;;
*)
{
error "Unrecognized option '$1' passed to _execute. Exiting."
return 1
}
;;
esac
done
shift $((OPTIND - 1))
[[ $# -lt 1 ]] && fatal 'Missing required argument to _cleanString_()!'
local string="${1}"
local userChars="${2:-}"
local arrayToClean=()
IFS=',' read -r -a arrayToClean <<<"${userChars}"
# trim trailing/leading white space and duplicate spaces/tabs
string="$(echo "${string}" | awk '{$1=$1};1')"
local i
for i in "${arrayToClean[@]}"; do
debug "cleaning: $i"
string="$(echo "${string}" | sed "s/$i//g")"
done
("${lc}") \
&& string="$(echo "${string}" | tr '[:upper:]' '[:lower:]')"
("${uc}") \
&& string="$(echo "${string}" | tr '[:lower:]' '[:upper:]')"
if "${alphanumeric}" && "${us}"; then
string="$(echo "${string}" | tr -c '[:alnum:]_ -' ' ')"
elif "${alphanumeric}"; then
string="$(echo "${string}" | sed "s/[^a-zA-Z0-9_ \-]//g")"
fi
if "${replace}"; then
string="$(echo "${string}" | sed -E "s/${pairs[0]}/${pairs[1]}/g")"
fi
# trim trailing/leading white space and duplicate dashes
string="$(echo "${string}" | tr -s '-' | tr -s '_')"
string="$(echo "${string}" | sed -E 's/([_\-]) /\1/g' | sed -E 's/ ([_\-])/\1/g')"
string="$(echo "${string}" | awk '{$1=$1};1')"
echo "${string}"
}
_stopWords_() {
# DESC: Removes common stopwords from a string
# ARGS: $1 (Required) - String to parse
# $2 (Optional) - Additional stopwords (comma separated)
# OUTS: Prints cleaned string to STDOUT
# USAGE: cleanName="$(_stopWords_ "[STRING]" "[MORE,STOP,WORDS]")"
# NOTE: Requires a stopwords file in sed format (expected at: ~/.sed/stopwords.sed)
[[ $# -lt 1 ]] && {
warning 'Missing required argument to _stripCommonWords_!'
return 1
}
if command -v gsed &>/dev/null; then
local SED_COMMAND="gsed"
elif sed --version | grep GNU &>/dev/null; then
local SED_COMMAND="sed"
else
error "Can not continue without gnu sed. Use '${yellow}brew install gnu-sed${reset} on a Mac or install with your package manager'"
return 1
fi
local string="${1}"
local sedFile="${HOME}/.sed/stopwords.sed"
if [ -f "${sedFile}" ]; then
string="$(echo "${string}" | ${SED_COMMAND} -f "${sedFile}")"
else
error "Missing sedfile in _stopWords_()"
return 1
fi
declare -a localStopWords=()
IFS=',' read -r -a localStopWords <<<"${2:-}"
if [[ ${#localStopWords[@]} -gt 0 ]]; then
for w in "${localStopWords[@]}"; do
string="$(echo "${string}" | ${SED_COMMAND} -E "s/\b${w}\b//gI")"
done
fi
# Remove double spaces and trim left/right
string="$(echo "${string}" | ${SED_COMMAND} -E 's/[ ]{2,}/ /g' | _ltrim_ | _rtrim_)"
echo "${string}"
}
_escape_() {
# DESC: Escapes a string by adding \ before special chars
# ARGS: $@ (Required) - String to be escaped
# OUTS: Prints output to STDOUT
# USAGE: _escape_ "Some text here"
# shellcheck disable=2001
echo "${@}" | sed 's/[]\.|$[ (){}?+*^]/\\&/g'
}
_htmlDecode_() {
# DESC: Decode HTML characters with sed
# ARGS: $1 (Required) - String to be decoded
# OUTS: Prints output to STDOUT
# USAGE: _htmlDecode_ <string>
# NOTE: Must have a sed file containing replacements
[[ $# -lt 1 ]] && {
error 'Missing required argument to _htmlDecode_()!'
return 1
}
local sedFile
sedFile="${HOME}/.sed/htmlDecode.sed"
[ -f "${sedFile}" ] \
&& { echo "${1}" | sed -f "${sedFile}"; } \
|| return 1
}
_htmlEncode_() {
# DESC: Encode HTML characters with sed
# ARGS: $1 (Required) - String to be encoded
# OUTS: Prints output to STDOUT
# USAGE: _htmlEncode_ <string>
# NOTE: Must have a sed file containing replacements
[[ $# -lt 1 ]] && {
error 'Missing required argument to _htmlEncode_()!'
return 1
}
local sedFile
sedFile="${HOME}/.sed/htmlEncode.sed"
[ -f "${sedFile}" ] \
&& { echo "${1}" | sed -f "${sedFile}"; } \
|| return 1
}
_lower_() {
# DESC: Convert a string to lowercase
# ARGS: None
# OUTS: None
# USAGE: text=$(_lower_ <<<"$1")
# echo "STRING" | _lower_
tr '[:upper:]' '[:lower:]'
}
_upper_() {
# DESC: Convert a string to uppercase
# ARGS: None
# OUTS: None
# USAGE: text=$(_upper_ <<<"$1")
# echo "STRING" | _upper_
tr '[:lower:]' '[:upper:]'
}
_ltrim_() {
# DESC: Removes all leading whitespace (from the left)
# ARGS: None
# OUTS: None
# USAGE: text=$(_ltrim_ <<<"$1")
# echo "STRING" | _ltrim_
local char=${1:-[:space:]}
sed "s%^[${char//%/\\%}]*%%"
}
_regex_() {
# DESC: Use regex to validate and parse strings
# ARGS: $1 (Required) - Input String
# $2 (Required) - Regex pattern
# OUTS: Prints string matching regex
# Returns error if no part of string did not match regex
# USAGE: _regex_ "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
# NOTE: This example only prints the first matching group. When using multiple capture
# groups some modification is needed.
# https://github.com/dylanaraps/pure-bash-bible
if [[ $1 =~ $2 ]]; then
printf '%s\n' "${BASH_REMATCH[1]}"
return 0
else
return 1
fi
}
_rtrim_() {
# DESC: Removes all leading whitespace (from the right)
# ARGS: None
# OUTS: None
# USAGE: text=$(_rtrim_ <<<"$1")
# echo "STRING" | _rtrim_
local char=${1:-[:space:]}
sed "s%[${char//%/\\%}]*$%%"
}
_trim_() {
# DESC: Removes all leading/trailing whitespace
# ARGS: None
# OUTS: None
# USAGE: text=$(_trim_ <<<"$1")
# echo "STRING" | _trim_
awk '{$1=$1;print}'
}
_urlEncode_() {
# DESC: URL encode a string
# ARGS: $1 (Required) - String to be encoded
# OUTS: Prints output to STDOUT
# USAGE: _urlEncode_ <string>
# NOTE: https://gist.github.com/cdown/1163649
[[ $# -lt 1 ]] && {
error 'Missing required argument to _urlEncode_()!'
return 1
}
local LANG=C
local i
for ((i = 0; i < ${#1}; i++)); do
if [[ ${1:i:1} =~ ^[a-zA-Z0-9\.\~_-]$ ]]; then
printf "${1:i:1}"
else
printf '%%%02X' "'${1:i:1}"
fi
done
}
_urlDecode_() {
# DESC: Decode a URL encoded string
# ARGS: $1 (Required) - String to be decoded
# OUTS: Prints output to STDOUT
# USAGE: _urlDecode_ <string>
[[ $# -lt 1 ]] && {
error 'Missing required argument to _urlDecode_()!'
return 1
}
local url_encoded="${1//+/ }"
printf '%b' "${url_encoded//%/\\x}"
}