diff --git a/utilities/alerts.bash b/utilities/alerts.bash index 4141e13..8c85a55 100644 --- a/utilities/alerts.bash +++ b/utilities/alerts.bash @@ -1,139 +1,140 @@ - # Colors if tput setaf 1 &>/dev/null; then - bold=$(tput bold) - white=$(tput setaf 7) - reset=$(tput sgr0) - purple=$(tput setaf 171) - red=$(tput setaf 1) - green=$(tput setaf 76) - tan=$(tput setaf 3) - yellow=$(tput setaf 3) - blue=$(tput setaf 38) - underline=$(tput sgr 0 1) + bold=$(tput bold) + white=$(tput setaf 7) + reset=$(tput sgr0) + purple=$(tput setaf 171) + red=$(tput setaf 1) + green=$(tput setaf 76) + tan=$(tput setaf 3) + yellow=$(tput setaf 3) + blue=$(tput setaf 38) + underline=$(tput sgr 0 1) else - bold="\033[4;37m" - white="\033[0;37m" - reset="\033[0m" - purple="\033[0;35m" - red="\033[0;31m" - green="\033[1;32m" - tan="\033[0;33m" - yellow="\033[0;33m" - blue="\033[0;34m" - underline="\033[4;37m" + bold="\033[4;37m" + white="\033[0;37m" + reset="\033[0m" + purple="\033[0;35m" + red="\033[0;31m" + green="\033[1;32m" + tan="\033[0;33m" + yellow="\033[0;33m" + blue="\033[0;34m" + underline="\033[4;37m" fi _alert_() { - # 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 + # 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 - local function_name color - local alertType="${1}" - local message="${2}" - local line="${3:-}" # Optional line number + local function_name 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_)" - fi - - if [[ "${alertType}" =~ ^(error|fatal) ]]; then - color="${bold}${red}" - 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}" =~ ^(input|notice) ]]; then - color="${bold}" - elif [ "${alertType}" = "dryrun" ]; then - color="${blue}" - else - color="" - fi - - _writeToScreen_() { - - ("${QUIET}") && return 0 # Print to console when script is not 'quiet' - [[ ${VERBOSE} == false && "${alertType}" =~ ^(debug|verbose) ]] && return 0 - - if ! [[ -t 1 ]]; then # Don't use colors on non-recognized terminals - color="" - reset="" + 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_)" fi - echo -e "$(date +"%r") ${color}$(printf "[%7s]" "${alertType}") ${message}${reset}" - } - _writeToScreen_ - - _writeToLog_() { - [[ "${alertType}" == "input" ]] && return 0 - [[ "${LOGLEVEL}" =~ (off|OFF|Off) ]] && return 0 - [ -z "${LOGFILE:-}" ] && fatal "\$LOGFILE must be set" - [ ! -d "$(dirname "${LOGFILE}")" ] && mkdir -p "$(dirname "${LOGFILE}")" - [[ ! -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')" + if [[ ${alertType} =~ ^(error|fatal) ]]; then + color="${bold}${red}" + 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} =~ ^(input|notice) ]]; then + color="${bold}" + elif [ "${alertType}" = "dryrun" ]; then + color="${blue}" else - local cleanmessage="$(echo "${message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')" + color="" fi - echo -e "$(date +"%b %d %R:%S") $(printf "[%7s]" "${alertType}") [$(/bin/hostname)] ${cleanmessage}" >>"${LOGFILE}" - } -# Write specified log level data to LOGFILE -case "${LOGLEVEL:-ERROR}" in - ALL|all|All) - _writeToLog_ - ;; - DEBUG|debug|Debug) - _writeToLog_ - ;; - INFO|info|Info) - if [[ "${alertType}" =~ ^(die|error|fatal|warning|info|notice|success) ]]; then - _writeToLog_ - fi - ;; - WARN|warn|Warn) - if [[ "${alertType}" =~ ^(die|error|fatal|warning) ]]; then - _writeToLog_ - fi - ;; - ERROR|error|Error) - if [[ "${alertType}" =~ ^(die|error|fatal) ]]; then - _writeToLog_ - fi - ;; - FATAL|fatal|Fatal) - if [[ "${alertType}" =~ ^(die|fatal) ]]; then - _writeToLog_ - fi - ;; - OFF|off) - return 0 - ;; - *) - if [[ "${alertType}" =~ ^(die|error|fatal) ]]; then - _writeToLog_ - fi - ;; -esac + _writeToScreen_() { + + ("${QUIET}") && return 0 # Print to console when script is not 'quiet' + [[ ${VERBOSE} == false && ${alertType} =~ ^(debug|verbose) ]] && return 0 + + if ! [[ -t 1 ]]; then # Don't use colors on non-recognized terminals + color="" + reset="" + fi + + echo -e "$(date +"%r") ${color}$(printf "[%7s]" "${alertType}") ${message}${reset}" + } + _writeToScreen_ + + _writeToLog_() { + [[ ${alertType} == "input" ]] && return 0 + [[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0 + if [ -z "${LOGFILE:-}" ]; then + LOGFILE="$(pwd)/$(basename "$0").log" + fi + [ ! -d "$(dirname "${LOGFILE}")" ] && mkdir -p "$(dirname "${LOGFILE}")" + [[ ! -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}" + } + + # Write specified log level data to logfile + case "${LOGLEVEL:-ERROR}" in + ALL | all | All) + _writeToLog_ + ;; + DEBUG | debug | Debug) + _writeToLog_ + ;; + INFO | info | Info) + if [[ ${alertType} =~ ^(die|error|fatal|warning|info|notice|success) ]]; then + _writeToLog_ + fi + ;; + WARN | warn | Warn) + if [[ ${alertType} =~ ^(die|error|fatal|warning) ]]; then + _writeToLog_ + fi + ;; + ERROR | error | Error) + if [[ ${alertType} =~ ^(die|error|fatal) ]]; then + _writeToLog_ + fi + ;; + FATAL | fatal | Fatal) + if [[ ${alertType} =~ ^(die|fatal) ]]; then + _writeToLog_ + fi + ;; + OFF | off) + return 0 + ;; + *) + if [[ ${alertType} =~ ^(die|error|fatal) ]]; then + _writeToLog_ + fi + ;; + esac } # /_alert_ @@ -145,24 +146,30 @@ success() { _alert_ success "${1}" "${2:-}"; } dryrun() { _alert_ dryrun "${1}" "${2:-}"; } input() { _alert_ input "${1}" "${2:-}"; } header() { _alert_ header "== ${1} ==" "${2:-}"; } -die() { _alert_ fatal "${1}" "${2:-}"; _safeExit_ "1" ; } -fatal() { _alert_ fatal "${1}" "${2:-}"; _safeExit_ "1" ; } +die() { + _alert_ fatal "${1}" "${2:-}" + _safeExit_ "1" +} +fatal() { + _alert_ fatal "${1}" "${2:-}" + _safeExit_ "1" +} debug() { _alert_ debug "${1}" "${2:-}"; } verbose() { _alert_ debug "${1}" "${2:-}"; } _functionStack_() { - # DESC: Prints the function stack in use - # ARGS: None - # OUTS: Prints [function]:[file]:[line] - # NOTE: Does not print functions from the alert class - local _i - funcStackResponse=() - for ((_i = 1; _i < ${#BASH_SOURCE[@]}; _i++)); do - case "${FUNCNAME[$_i]}" in "_alert_" | "_trapCleanup_" | fatal | error | warning | verbose | debug | die) continue ;; esac - funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[$_i - 1]}") - done - printf "( " - printf %s "${funcStackResponse[0]}" - printf ' < %s' "${funcStackResponse[@]:1}" - printf ' )\n' + # DESC: Prints the function stack in use + # ARGS: None + # OUTS: Prints [function]:[file]:[line] + # NOTE: Does not print functions from the alert class + local _i + 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]}") + done + printf "( " + printf %s "${funcStackResponse[0]}" + printf ' < %s' "${funcStackResponse[@]:1}" + printf ' )\n' } diff --git a/utilities/arrays.bash b/utilities/arrays.bash index 1839fa3..56ec2f5 100644 --- a/utilities/arrays.bash +++ b/utilities/arrays.bash @@ -1,83 +1,82 @@ - _inArray_() { - # DESC: Determine if a value is in an array - # ARGS: $1 (Required) - Value to search for - # $2 (Required) - Array written as ${ARRAY[@]} - # OUTS: true/false - # USAGE: if _inArray_ "VALUE" "${ARRAY[@]}"; then ... + # DESC: Determine if a value is in an array + # ARGS: $1 (Required) - Value to search for + # $2 (Required) - Array written as ${ARRAY[@]} + # OUTS: true/false + # USAGE: if _inArray_ "VALUE" "${ARRAY[@]}"; then ... - [[ $# -lt 2 ]] && fatal 'Missing required argument to _inArray_()!' + [[ $# -lt 2 ]] && fatal 'Missing required argument to _inArray_()!' - local value="$1" - shift - for arrayItem in "$@"; do - [[ "${arrayItem}" == "${value}" ]] && return 0 - done - return 1 + local value="$1" + shift + for arrayItem in "$@"; do + [[ ${arrayItem} == "${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 - # 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 + # DESC: Joins items together with a user specified separator + # ARGS: $1 (Required) - Separator + # $@ (Required) - Items to be joined + # OUTS: 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 + # NOTE: http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array - [[ $# -lt 2 ]] && fatal 'Missing required argument to _join_()!' + [[ $# -lt 2 ]] && fatal 'Missing required argument to _join_()!' - local IFS="${1}" - shift - echo "${*}" + local IFS="${1}" + shift + echo "${*}" } _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 + # 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 - [[ $# -lt 2 ]] && fatal 'Missing required argument to _setdiff_()!' + [[ $# -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 + 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 - [[ "$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[@]}" + [[ "$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[@]}" } _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 + # 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 for i in "$@"; do @@ -88,11 +87,11 @@ _removeDupes_() { } _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 + # 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 % $#]}" diff --git a/utilities/baseHelpers.bash b/utilities/baseHelpers.bash index 038a7d7..2cb6172 100644 --- a/utilities/baseHelpers.bash +++ b/utilities/baseHelpers.bash @@ -1,361 +1,360 @@ - _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 - # -p Pass a failed command with 'return 0'. This effecively 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` + # 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 + # -p Pass a failed command with 'return 0'. This effecively 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 localVerbose=false - local passFailures=false - local echoResult=false - local successResult=false - local quietResult=false - local opt + local LOCAL_VERBOSE=false + local PASS_FAILURES=false + local ECHO_RESULT=false + local SUCCESS_RESULT=false + local QUIET_RESULT=false + local opt - local OPTIND=1 - while getopts ":vVpPeEsSqQ" opt; do - case $opt in - v | V) localVerbose=true ;; - p | P) passFailures=true ;; - e | E) echoResult=true ;; - s | S) successResult=true ;; - q | Q) quietResult=true ;; - *) - { - error "Unrecognized option '$1' passed to _execute_. Exiting." - _safeExit_ - } - ;; - esac - done - shift $((OPTIND - 1)) + local OPTIND=1 + while getopts ":vVpPeEsSqQ" 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 ;; + *) + { + error "Unrecognized option '$1' passed to _execute_. Exiting." + _safeExit_ + } + ;; + esac + done + shift $((OPTIND - 1)) - local cmd="${1:?_execute_ needs a command}" - local message="${2:-$1}" + local CMD="${1:?_execute_ needs a command}" + local EXECUTE_MESSAGE="${2:-$1}" - local saveVerbose=$VERBOSE - if "${localVerbose}"; then - VERBOSE=true - fi - - if "${DRYRUN}"; then - if "$quietResult"; then - VERBOSE=$saveVerbose - return 0 + local SAVE_VERBOSE=${VERBOSE} + if "${LOCAL_VERBOSE}"; then + VERBOSE=true fi - if [ -n "${2:-}" ]; then - dryrun "${1} (${2})" "$(caller)" + + 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 "${ECHO_RESULT}"; then + echo "${EXECUTE_MESSAGE}" + elif "${SUCCESS_RESULT}"; then + success "${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 - dryrun "${1}" "$(caller)" + 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}" + 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 - elif ${VERBOSE}; then - if eval "${cmd}"; then - if "$echoResult"; then - echo "${message}" - elif "${successResult}"; then - success "${message}" - else - info "${message}" - fi - VERBOSE=$saveVerbose - return 0 - else - if "$echoResult"; then - echo "warning: ${message}" - else - warning "${message}" - fi - VERBOSE=$saveVerbose - "${passFailures}" && return 0 || return 1 - fi - else - if eval "${cmd}" &>/dev/null; then - if "$quietResult"; then - VERBOSE=$saveVerbose - return 0 - elif "$echoResult"; then - echo "${message}" - elif "${successResult}"; then - success "${message}" - else - info "${message}" - fi - VERBOSE=$saveVerbose - return 0 - else - if "$echoResult"; then - echo "error: ${message}" - else - warning "${message}" - fi - VERBOSE=$saveVerbose - "${passFailures}" && 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" + # 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 + local SOURCE + local DIR - # Is file sourced? - [[ $_ != "$0" ]] \ - && SOURCE="${BASH_SOURCE[1]}" \ - || SOURCE="${BASH_SOURCE[0]}" + # 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)" + 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 + # 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 + 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" + # 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 + 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 + # 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?" + local pauseMessage + pauseMessage="${1:-Paused}. Ready to continue?" - if _seekConfirmation_ "${pauseMessage}"; then - info "Continuing..." - else - notice "Exiting Script" - _safeExit_ - fi + 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 + # 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 + ($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 + 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="#" + 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 + # 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})) + 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 - # 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 + 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 + # 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 + 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 fi - fi - if [[ -z ${superuser:-} ]]; then - notice 'Unable to acquire superuser credentials.' - return 1 - fi + if [[ -z ${superuser:-} ]]; then + notice 'Unable to acquire superuser credentials.' + return 1 + fi - info 'Successfully acquired superuser credentials.' - return 0 + info '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 + # 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 [[ $# -eq 0 ]]; then + fatal 'Missing required argument to _runAsRoot_()!' + fi - if [[ ${1:-} =~ ^0$ ]]; then - local skip_sudo=true - shift - 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 + 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 + # 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 - 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 + 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 + # 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 USERPATH in "$@"; do + NEWPATHS+=("$USERPATH") + done - for NEWPATH in "${NEWPATHS[@]}"; do - if ! echo "$PATH" | grep -Eq "(^|:)${NEWPATH}($|:)"; then - PATH="${NEWPATH}:${PATH}" - debug "Added '${tan}${NEWPATH}${purple}' to PATH" - fi - done + for NEWPATH in "${NEWPATHS[@]}"; do + if ! echo "$PATH" | grep -Eq "(^|:)${NEWPATH}($|:)"; then + PATH="${NEWPATH}:${PATH}" + debug "Added '${tan}${NEWPATH}${purple}' to PATH" + fi + done } _safeExit_() { - # DESC: Cleanup and exit from a script - # ARGS: $1 (optional) - Exit code (defaults to 0) - # OUTS: None + # 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}" + 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 - fi - if [[ -n "${tmpDir:-}" && -d "${tmpDir:-}" ]]; then - if [[ ${1:-} == 1 && -n "$(ls "${tmpDir}")" ]]; then - command rm -r "${tmpDir}" - else - command rm -r "${tmpDir}" - debug "Removing temp directory" + 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 - fi - trap - INT TERM EXIT - exit ${1:-0} + trap - INT TERM EXIT + exit ${1:-0} } diff --git a/utilities/csv.bash b/utilities/csv.bash index 18a6f0d..06750f8 100644 --- a/utilities/csv.bash +++ b/utilities/csv.bash @@ -1,34 +1,34 @@ _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' + # 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}" + # Set the location and name of the CSV File + if [ -z "${csvLocation}" ]; then + csvLocation="${HOME}/Desktop" fi - fi - _writeCSV_ "$@" + 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' + # 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} + local csvInput=("$@") + saveIFS=$IFS + IFS=',' + echo "${csvInput[*]}" >>"${csvFile}" + IFS=${saveIFS} } diff --git a/utilities/dates.bash b/utilities/dates.bash index 7305b2a..db54d7c 100644 --- a/utilities/dates.bash +++ b/utilities/dates.bash @@ -1,381 +1,392 @@ _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: None + # OUTS: Prints the number of the month to stdout + # USAGE: _monthToNumber_ "January" - 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 ;; - june|jun|ju) echo 6 ;; - july|jul) echo 7 ;; - august|aug|au) echo 8 ;; - september|sep|se) echo 9 ;; - october|oct) echo 10 ;; - november|nov|no) echo 11 ;; - december|dec|de) echo 12 ;; - *) - warning "month_monthToNumber_: Bad monthname: $1" - return 1 ;; - esac + 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 ;; + june | jun | ju) echo 6 ;; + july | jul) echo 7 ;; + august | aug | au) echo 8 ;; + september | sep | se) echo 9 ;; + october | oct) echo 10 ;; + november | nov | no) echo 11 ;; + december | dec | de) echo 12 ;; + *) + warning "month_monthToNumber_: Bad monthname: $1" + 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: None + # OUTS: Prints the name of the month to stdout + # USAGE: _numberToMonth_ 1 - 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 ;; - 6|06) echo June ;; - 7|07) echo July ;; - 8|08) echo August ;; - 9|09) echo September ;; - 10) echo October ;; - 11) echo November ;; - 12) echo December ;; - *) - warning "_numberToMonth_: Bad month number: $1" - return 1 ;; - esac + 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 ;; + 6 | 06) echo June ;; + 7 | 07) echo July ;; + 8 | 08) echo August ;; + 9 | 09) echo September ;; + 10) echo October ;; + 11) echo November ;; + 12) echo December ;; + *) + warning "_numberToMonth_: Bad month number: $1" + 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 '-_ ./' - # * YYYY-MM-DD * Month DD, YYYY * DD Month, YYYY - # * Month, YYYY * Month, DD YY * MM-DD-YYYY - # * MMDDYYYY * YYYYMMDD * DDMMYYYY - # * YYYYMMDDHHMM * YYYYMMDDHH * DD-MM-YYYY - # * DD MM YY * MM DD YY - # TODO: Impelemt the following date formats - # * MMDDYY * YYMMDD * mon-DD-YY + # 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 '-_ ./' + # * YYYY-MM-DD * Month DD, YYYY * DD Month, YYYY + # * Month, YYYY * Month, DD YY * MM-DD-YYYY + # * MMDDYYYY * YYYYMMDD * DDMMYYYY + # * YYYYMMDDHHMM * YYYYMMDDHH * DD-MM-YYYY + # * DD MM YY * MM DD YY + # TODO: Impelemt the following date formats + # * MMDDYY * YYMMDD * mon-DD-YY - [[ $# -eq 0 ]] && { - error 'Missing required argument to _parseDate_()!' - return 1 - } - - local date="${1:-$(date +%F)}" - _parseDate_found="" _parseDate_year="" _parseDate_month="" _parseDate_monthName="" - _parseDate_day="" _parseDate_hour="" _parseDate_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]} )) - 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]:-} )) - 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]} ))" - 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]}" )) - 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 - - 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]} )) - 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 - ]]; 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]} )) - 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]} )) - debug "regex match: ${tan}MM-DD-YYYY${purple}" - else - shopt -u nocasematch + [[ $# -eq 0 ]] && { + error 'Missing required argument to _parseDate_()!' return 1 - fi + } - elif [[ "${date}" =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{2}))([^0-9].*|$) ]]; then + local date="${1:-$(date +%F)}" + _parseDate_found="" _parseDate_year="" _parseDate_month="" _parseDate_monthName="" + _parseDate_day="" _parseDate_hour="" _parseDate_minute="" - if [[ $(( 10#${BASH_REMATCH[3]} )) -lt 13 && \ - $(( 10#${BASH_REMATCH[4]} )) -gt 12 && \ - $(( 10#${BASH_REMATCH[4]} )) -lt 32 - ]]; then + 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]})) + 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]:-})) + 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]}))" + 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]}")) + 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 + + 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_year=$((10#${BASH_REMATCH[5]})) + _parseDate_month=$((10#${BASH_REMATCH[3]})) _parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")" - _parseDate_day=$(( 10#${BASH_REMATCH[4]} )) + _parseDate_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 - ]]; then + elif [[ $((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_year="20$(( 10#${BASH_REMATCH[5]} ))" - _parseDate_month=$(( 10#${BASH_REMATCH[4]} )) + _parseDate_year=$((10#${BASH_REMATCH[5]})) + _parseDate_month=$((10#${BASH_REMATCH[4]})) _parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")" - _parseDate_day=$(( 10#${BASH_REMATCH[3]} )) + _parseDate_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]} )) - debug "regex match: ${tan}MM-DD-YYYY${purple}" - else - shopt -u nocasematch - return 1 - fi + 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]})) + debug "regex match: ${tan}MM-DD-YYYY${purple}" + else + shopt -u nocasematch + return 1 + 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]} ))" - debug "regex match: ${tan}Month, YYYY${purple}" + elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{2}))([^0-9].*|$) ]]; then - # 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]} ))" - debug "regex match: ${tan}YYYYMMDDHHMM${purple}" + 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]})) + 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 ]] \ + ; 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]})) + 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]})) + debug "regex match: ${tan}MM-DD-YYYY${purple}" + else + shopt -u nocasematch + return 1 + fi - # 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" - debug "regex match: ${tan}YYYYMMDDHHMM${purple}" + # 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]}))" + debug "regex match: ${tan}Month, YYYY${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 + # 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]}))" + 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" + 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 # MMDDYYYY - if [[ $(( 10#${BASH_REMATCH[5]} )) -eq 20 && \ - $(( 10#${BASH_REMATCH[3]} )) -lt 13 && \ - $(( 10#${BASH_REMATCH[4]} )) -lt 32 - ]]; then + if [[ $((10#${BASH_REMATCH[5]})) -eq 20 && + $((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_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}" # 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 - ]]; then + 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 ]] \ + ; then _parseDate_found="${BASH_REMATCH[2]}" - _parseDate_day="$(( 10#${BASH_REMATCH[3]} ))" - _parseDate_month="$(( 10#${BASH_REMATCH[4]} ))" + _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}" # 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 \ - ]]; then + 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 ]] \ + ; then _parseDate_found="${BASH_REMATCH[2]}" - _parseDate_day="$(( 10#${BASH_REMATCH[6]} ))" - _parseDate_month="$(( 10#${BASH_REMATCH[5]} ))" + _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}" # 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 \ - ]]; then + 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 ]] \ + ; then _parseDate_found="${BASH_REMATCH[2]}" - _parseDate_day="$(( 10#${BASH_REMATCH[5]} ))" - _parseDate_month="$(( 10#${BASH_REMATCH[6]} ))" + _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}" # Assume YYYMMDD - elif [[ $(( 10#${BASH_REMATCH[3]} )) -eq 20 \ - && $(( 10#${BASH_REMATCH[6]} )) -lt 32 \ - && $(( 10#${BASH_REMATCH[5]} )) -lt 13 \ - ]]; then + elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 && + $((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_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}" else - shopt -u nocasematch - return 1 + shopt -u nocasematch + return 1 fi - # # MMDD or DDYY - # elif [[ "$date" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then - # debug "regex match: ${tan}MMDD or DDMM${purple}" - # _parseDate_found="${BASH_REMATCH[1]}" + # # MMDD or DDYY + # elif [[ "$date" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then + # debug "regex match: ${tan}MMDD or DDMM${purple}" + # _parseDate_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 )" + # 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 )" + # else + # shopt -u nocasematch + # return 1 + # fi + else + shopt -u nocasematch + return 1 + + fi + + [[ -z ${_parseDate_year:-} ]] && { + shopt -u nocasematch + return 1 + } + ((_parseDate_month >= 1 && _parseDate_month <= 12)) || { + shopt -u nocasematch + return 1 + } + ((_parseDate_day >= 1 && _parseDate_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}" - # # 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 )" - # 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 )" - # else - # shopt -u nocasematch - # return 1 - # fi - else shopt -u nocasematch - return 1 - fi - - [[ -z ${_parseDate_year:-} ]] && { shopt -u nocasematch; return 1 ; } - (( _parseDate_month >= 1 && _parseDate_month <= 12 )) || { shopt -u nocasematch; return 1 ; } - (( _parseDate_day >= 1 && _parseDate_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}" - - 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}" - fi + # 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}" + 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) + # 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) - [[ $# -eq 0 ]] && { - error 'Missing required argument to _formatDate_()' - return 1 - } + [[ $# -eq 0 ]] && { + error 'Missing required argument to _formatDate_()' + return 1 + } - local d="${1}" - local format="${2:-%F}" - format="${format//+/}" + local d="${1}" + local format="${2:-%F}" + format="${format//+/}" - if command -v gdate >/dev/null 2>&1; then - gdate -d "${d}" "+${format}" - else - date -d "${d}" "+${format}" - fi + if command -v gdate >/dev/null 2>&1; then + gdate -d "${d}" "+${format}" + else + date -d "${d}" "+${format}" + fi } diff --git a/utilities/files.bash b/utilities/files.bash index 3684455..fae170f 100644 --- a/utilities/files.bash +++ b/utilities/files.bash @@ -1,474 +1,473 @@ _listFiles_() { - # DESC: Find files in a directory. Use either glob or regex - # ARGS: $1 (Required) - 'g|glob' or 'r|regex' - # $2 (Required) - pattern to match - # $3 (Optional) - directory - # OUTS: Prints files to STDOUT - # NOTE: Searches are NOT case sensitive and MUST be quoted - # USAGE: _listFiles_ glob "*.txt" "some/backup/dir" - # _listFiles_ regex ".*\.txt" "some/backup/dir" - # readarry -t array < <(_listFiles_ g "*.txt") + # DESC: Find files in a directory. Use either glob or regex + # ARGS: $1 (Required) - 'g|glob' or 'r|regex' + # $2 (Required) - pattern to match + # $3 (Optional) - directory + # OUTS: Prints files to STDOUT + # NOTE: Searches are NOT case sensitive and MUST be quoted + # USAGE: _listFiles_ glob "*.txt" "some/backup/dir" + # _listFiles_ regex ".*\.txt" "some/backup/dir" + # readarry -t array < <(_listFiles_ g "*.txt") - [[ $# -lt 2 ]] && { - error 'Missing required argument to _listFiles_()!' - return 1 - } + [[ $# -lt 2 ]] && { + error 'Missing required argument to _listFiles_()!' + return 1 + } - local t="${1}" - local p="${2}" - local d="${3:-.}" - local fileMatch e + local t="${1}" + local p="${2}" + local d="${3:-.}" + local fileMatch e - case "$t" in - glob | Glob | g | G) - while read -r fileMatch; do - e="$(realpath "${fileMatch}")" - echo "${e}" - done < <(find "${d}" -iname "${p}" -type f -maxdepth 1 | sort) - ;; - regex | Regex | r | R) - while read -r fileMatch; do - e="$(realpath "${fileMatch}")" - echo "${e}" - done < <(find "${d}" -iregex "${p}" -type f -maxdepth 1 | sort) - ;; - *) - echo "Could not determine if search was glob or regex" - return 1 - ;; - esac + case "$t" in + glob | Glob | g | G) + while read -r fileMatch; do + e="$(realpath "${fileMatch}")" + echo "${e}" + done < <(find "${d}" -iname "${p}" -type f -maxdepth 1 | sort) + ;; + regex | Regex | r | R) + while read -r fileMatch; do + e="$(realpath "${fileMatch}")" + echo "${e}" + done < <(find "${d}" -iregex "${p}" -type f -maxdepth 1 | sort) + ;; + *) + echo "Could not determine if search was glob or regex" + return 1 + ;; + esac } _backupFile_() { - # DESC: Creates a backup of a specified file with .bak extension or - # optionally to a specified directory - # ARGS: $1 (Required) - Source file - # $2 (Optional) - Destination dir name used only with -d flag (defaults to ./backup) - # OPTS: -d - Move files to a backup direcory - # -m - Replaces copy (default) with move, effectively removing the - # OUTS: None - # USAGE: _backupFile_ "sourcefile.txt" "some/backup/dir" - # NOTE: dotfiles have their leading '.' removed in their backup + # DESC: Creates a backup of a specified file with .bak extension or + # optionally to a specified directory + # ARGS: $1 (Required) - Source file + # $2 (Optional) - Destination dir name used only with -d flag (defaults to ./backup) + # OPTS: -d - Move files to a backup direcory + # -m - Replaces copy (default) with move, effectively removing the + # OUTS: None + # USAGE: _backupFile_ "sourcefile.txt" "some/backup/dir" + # NOTE: dotfiles have their leading '.' removed in their backup - local opt - local OPTIND=1 - local useDirectory=false - local moveFile=false + local opt + local OPTIND=1 + local useDirectory=false + local moveFile=false - while getopts ":dDmM" opt; do - case ${opt} in - d | D) useDirectory=true ;; - m | M) moveFile=true ;; - *) - { - error "Unrecognized option '$1' passed to _makeSymlink_" "${LINENO}" - return 1 + while getopts ":dDmM" opt; do + case ${opt} in + d | D) useDirectory=true ;; + m | M) moveFile=true ;; + *) + { + error "Unrecognized option '$1' passed to _makeSymlink_" "${LINENO}" + return 1 + } + ;; + esac + done + shift $((OPTIND - 1)) + + [[ $# -lt 1 ]] && fatal 'Missing required argument to _backupFile_()!' + + local s="${1}" + local d="${2:-backup}" + local n # New filename (created by _uniqueFilename_) + + # Error handling + [ ! "$(declare -f "_execute_")" ] \ + && { + warning "need function _execute_" + return 1 + } + [ ! "$(declare -f "_uniqueFileName_")" ] \ + && { + warning "need function _uniqueFileName_" + return 1 + } + [ ! -e "$s" ] \ + && { + warning "Source '${s}' not found" + return 1 } - ;; - esac - done - shift $((OPTIND - 1)) - [[ $# -lt 1 ]] && fatal 'Missing required argument to _backupFile_()!' + if [ ${useDirectory} == true ]; then - local s="${1}" - local d="${2:-backup}" - local n # New filename (created by _uniqueFilename_) + [ ! -d "${d}" ] \ + && _execute_ "mkdir -p \"${d}\"" "Creating backup directory" - # Error handling - [ ! "$(declare -f "_execute_")" ] \ - && { - warning "need function _execute_" - return 1 - } - [ ! "$(declare -f "_uniqueFileName_")" ] \ - && { - warning "need function _uniqueFileName_" - return 1 - } - [ ! -e "$s" ] \ - && { - warning "Source '${s}' not found" - return 1 - } - - if [ ${useDirectory} == true ]; then - - [ ! -d "${d}" ] \ - && _execute_ "mkdir -p \"${d}\"" "Creating backup directory" - - if [ -e "$s" ]; then - n="$(basename "${s}")" - n="$(_uniqueFileName_ "${d}/${s#.}")" - if [ ${moveFile} == true ]; then - _execute_ "mv \"${s}\" \"${d}/${n##*/}\"" "Moving: '${s}' to '${d}/${n##*/}'" - else - _execute_ "cp -R \"${s}\" \"${d}/${n##*/}\"" "Backing up: '${s}' to '${d}/${n##*/}'" - fi - fi - else - n="$(_uniqueFileName_ "${s}.bak")" - if [ ${moveFile} == true ]; then - _execute_ "mv \"${s}\" \"${n}\"" "Moving '${s}' to '${n}'" + if [ -e "$s" ]; then + n="$(basename "${s}")" + n="$(_uniqueFileName_ "${d}/${s#.}")" + if [ ${moveFile} == true ]; then + _execute_ "mv \"${s}\" \"${d}/${n##*/}\"" "Moving: '${s}' to '${d}/${n##*/}'" + else + _execute_ "cp -R \"${s}\" \"${d}/${n##*/}\"" "Backing up: '${s}' to '${d}/${n##*/}'" + fi + fi else - _execute_ "cp -R \"${s}\" \"${n}\"" "Backing up '${s}' to '${n}'" + n="$(_uniqueFileName_ "${s}.bak")" + if [ ${moveFile} == true ]; then + _execute_ "mv \"${s}\" \"${n}\"" "Moving '${s}' to '${n}'" + else + _execute_ "cp -R \"${s}\" \"${n}\"" "Backing up '${s}' to '${n}'" + fi fi - fi } _parseFilename_() { - # DESC: Break a filename into its component parts which and place them into prefixed - # variables for use in your script. Run with VERBOSE=true to see the variables while - # running your script. - # ARGS: $1 (Required) - File - # OPTS: -n - optional flag for number of extension levels (Ex: -n2) - # OUTS: $PARSE_FULL - File and its real path (ie, resolve symlinks) - # $PARSE_PATH - Path to the file - # $PARSE_BASE - Name of the file WITH extension - # $PARSE_BASENOEXT - Name of file WITHOUT extension - # $PARSE_EXT - The extension of the file - # USAGE: _parseFilename_ "some/file.txt" + # DESC: Break a filename into its component parts which and place them into prefixed + # variables for use in your script. Run with VERBOSE=true to see the variables while + # running your script. + # ARGS: $1 (Required) - File + # OPTS: -n - optional flag for number of extension levels (Ex: -n2) + # OUTS: $PARSE_FULL - File and its real path (ie, resolve symlinks) + # $PARSE_PATH - Path to the file + # $PARSE_BASE - Name of the file WITH extension + # $PARSE_BASENOEXT - Name of file WITHOUT extension + # $PARSE_EXT - The extension of the file + # USAGE: _parseFilename_ "some/file.txt" - # Error handling - if [[ $# -lt 1 ]] \ - || ! command -v dirname &>/dev/null \ - || ! command -v basename &>/dev/null \ - || ! command -v realpath &>/dev/null; then + # Error handling + if [[ $# -lt 1 ]] \ + || ! command -v dirname &>/dev/null \ + || ! command -v basename &>/dev/null \ + || ! command -v realpath &>/dev/null; then - fatal "Missing dependency or input to _parseFilename_()" - return 1 - fi - - local levels - local option - local exts - local ext - local i - local fn - - unset OPTIND - while getopts ":n:" option; do - case ${option} in - n) levels=${OPTARG} ;; - *) continue ;; - esac - done && shift $((OPTIND - 1)) - - local fileToParse="${1}" - - - [[ -f "${fileToParse}" ]] || { - error "Can't locate a file to parse at: ${fileToParse}" - return 1 - } - - PARSE_FULL="$(realpath "${fileToParse}")" \ - && debug "\${PARSE_FULL}: ${PARSE_FULL:-}" - PARSE_BASE=$(basename "${fileToParse}") \ - && debug "\${PARSE_BASE}: ${PARSE_BASE:-}" - PARSE_PATH="$(realpath "$(dirname "${fileToParse}")")" \ - && debug "\${PARSE_PATH}: ${PARSE_PATH:-}" - - # Detect some common multi-extensions - if [[ ! ${levels:-} ]]; then - case $(tr '[:upper:]' '[:lower:]' <<<"${PARSE_BASE}") in - *.tar.gz | *.tar.bz2) levels=2 ;; - esac - fi - - # Find Extension - levels=${levels:-1} - fn="${PARSE_BASE}" - for ((i = 0; i < levels; i++)); do - ext=${fn##*.} - if [ $i == 0 ]; then - exts=${ext}${exts:-} - else - exts=${ext}.${exts:-} + fatal "Missing dependency or input to _parseFilename_()" + return 1 fi - fn=${fn%.$ext} - done - if [[ "${exts}" == "${PARSE_BASE}" ]]; then - PARSE_EXT="" && debug "\${PARSE_EXT}: ${PARSE_EXT}" - else - PARSE_EXT="${exts}" && debug "\${PARSE_EXT}: ${PARSE_EXT}" - fi - PARSE_BASENOEXT="${PARSE_BASE%.$PARSE_EXT}" \ - && debug "\${PARSE_BASENOEXT}: ${PARSE_BASENOEXT}" + local levels + local option + local exts + local ext + local i + local fn + + unset OPTIND + while getopts ":n:" option; do + case ${option} in + n) levels=${OPTARG} ;; + *) continue ;; + esac + done && shift $((OPTIND - 1)) + + local fileToParse="${1}" + + [[ -f ${fileToParse} ]] || { + error "Can't locate a file to parse at: ${fileToParse}" + return 1 + } + + PARSE_FULL="$(realpath "${fileToParse}")" \ + && debug "\${PARSE_FULL}: ${PARSE_FULL:-}" + PARSE_BASE=$(basename "${fileToParse}") \ + && debug "\${PARSE_BASE}: ${PARSE_BASE:-}" + PARSE_PATH="$(realpath "$(dirname "${fileToParse}")")" \ + && debug "\${PARSE_PATH}: ${PARSE_PATH:-}" + + # Detect some common multi-extensions + if [[ ! ${levels:-} ]]; then + case $(tr '[:upper:]' '[:lower:]' <<<"${PARSE_BASE}") in + *.tar.gz | *.tar.bz2) levels=2 ;; + esac + fi + + # Find Extension + levels=${levels:-1} + fn="${PARSE_BASE}" + for ((i = 0; i < levels; i++)); do + ext=${fn##*.} + if [ $i == 0 ]; then + exts=${ext}${exts:-} + else + exts=${ext}.${exts:-} + fi + fn=${fn%.$ext} + done + if [[ ${exts} == "${PARSE_BASE}" ]]; then + PARSE_EXT="" && debug "\${PARSE_EXT}: ${PARSE_EXT}" + else + PARSE_EXT="${exts}" && debug "\${PARSE_EXT}: ${PARSE_EXT}" + fi + + PARSE_BASENOEXT="${PARSE_BASE%.$PARSE_EXT}" \ + && debug "\${PARSE_BASENOEXT}: ${PARSE_BASENOEXT}" } _decryptFile_() { - # DESC: Decrypts a file with openSSL - # ARGS: $1 (Required) - File to be decrypted - # $2 (Optional) - Name of output file (defaults to $1.decrypt) - # OUTS: None - # USAGE: _decryptFile_ "somefile.txt.enc" "decrypted_somefile.txt" - # NOTE: If a variable '$PASS' has a value, we will use that as the password - # to decrypt the file. Otherwise we will ask + # DESC: Decrypts a file with openSSL + # ARGS: $1 (Required) - File to be decrypted + # $2 (Optional) - Name of output file (defaults to $1.decrypt) + # OUTS: None + # USAGE: _decryptFile_ "somefile.txt.enc" "decrypted_somefile.txt" + # NOTE: If a variable '$PASS' has a value, we will use that as the password + # to decrypt the file. Otherwise we will ask - [[ $# -lt 1 ]] && fatal 'Missing required argument to _decryptFile_()!' + [[ $# -lt 1 ]] && fatal 'Missing required argument to _decryptFile_()!' - local fileToDecrypt decryptedFile defaultName - fileToDecrypt="${1:?_decryptFile_ needs a file}" - defaultName="${fileToDecrypt%.enc}" - decryptedFile="${2:-$defaultName.decrypt}" + local fileToDecrypt decryptedFile defaultName + fileToDecrypt="${1:?_decryptFile_ needs a file}" + defaultName="${fileToDecrypt%.enc}" + decryptedFile="${2:-$defaultName.decrypt}" - [ ! "$(declare -f "_execute_")" ] \ - && { - echo "need function _execute_" - return 1 - } + [ ! "$(declare -f "_execute_")" ] \ + && { + echo "need function _execute_" + return 1 + } - [ ! -f "$fileToDecrypt" ] && return 1 + [ ! -f "$fileToDecrypt" ] && return 1 - if [ -z "${PASS}" ]; then - _execute_ "openssl enc -aes-256-cbc -d -in \"${fileToDecrypt}\" -out \"${decryptedFile}\"" "Decrypt ${fileToDecrypt}" - else - _execute_ "openssl enc -aes-256-cbc -d -in \"${fileToDecrypt}\" -out \"${decryptedFile}\" -k \"${PASS}\"" "Decrypt ${fileToDecrypt}" - fi + if [ -z "${PASS}" ]; then + _execute_ "openssl enc -aes-256-cbc -d -in \"${fileToDecrypt}\" -out \"${decryptedFile}\"" "Decrypt ${fileToDecrypt}" + else + _execute_ "openssl enc -aes-256-cbc -d -in \"${fileToDecrypt}\" -out \"${decryptedFile}\" -k \"${PASS}\"" "Decrypt ${fileToDecrypt}" + fi } _encryptFile_() { - # DESC: Encrypts a file using openSSL - # ARGS: $1 (Required) - Input file - # $2 (Optional) - Name of output file (defaults to $1.enc) - # OUTS: None - # USAGE: _encryptFile_ "somefile.txt" "encrypted_somefile.txt" - # NOTE: If a variable '$PASS' has a value, we will use that as the password - # for the encrypted file. Otherwise we will ask. + # DESC: Encrypts a file using openSSL + # ARGS: $1 (Required) - Input file + # $2 (Optional) - Name of output file (defaults to $1.enc) + # OUTS: None + # USAGE: _encryptFile_ "somefile.txt" "encrypted_somefile.txt" + # NOTE: If a variable '$PASS' has a value, we will use that as the password + # for the encrypted file. Otherwise we will ask. - local fileToEncrypt encryptedFile defaultName + local fileToEncrypt encryptedFile defaultName - fileToEncrypt="${1:?_encodeFile_ needs a file}" - defaultName="${fileToEncrypt%.decrypt}" - encryptedFile="${2:-$defaultName.enc}" + fileToEncrypt="${1:?_encodeFile_ needs a file}" + defaultName="${fileToEncrypt%.decrypt}" + encryptedFile="${2:-$defaultName.enc}" - [ ! -f "$fileToEncrypt" ] && return 1 + [ ! -f "$fileToEncrypt" ] && return 1 - [ ! "$(declare -f "_execute_")" ] \ - && { - echo "need function _execute_" - return 1 - } + [ ! "$(declare -f "_execute_")" ] \ + && { + echo "need function _execute_" + return 1 + } - if [ -z "${PASS}" ]; then - _execute_ "openssl enc -aes-256-cbc -salt -in \"${fileToEncrypt}\" -out \"${encryptedFile}\"" "Encrypt ${fileToEncrypt}" - else - _execute_ "openssl enc -aes-256-cbc -salt -in \"${fileToEncrypt}\" -out \"${encryptedFile}\" -k \"${PASS}\"" "Encrypt ${fileToEncrypt}" - fi + if [ -z "${PASS}" ]; then + _execute_ "openssl enc -aes-256-cbc -salt -in \"${fileToEncrypt}\" -out \"${encryptedFile}\"" "Encrypt ${fileToEncrypt}" + else + _execute_ "openssl enc -aes-256-cbc -salt -in \"${fileToEncrypt}\" -out \"${encryptedFile}\" -k \"${PASS}\"" "Encrypt ${fileToEncrypt}" + fi } _extract_() { - # DESC: Extract a compressed file - # ARGS: $1 (Required) - Input file - # $2 (optional) - Input 'v' to show verbose output - # OUTS: None + # DESC: Extract a compressed file + # ARGS: $1 (Required) - Input file + # $2 (optional) - Input 'v' to show verbose output + # OUTS: None - local filename - local foldername - local fullpath - local didfolderexist - local vv + local filename + local foldername + local fullpath + local didfolderexist + local vv - [[ $# -lt 1 ]] && fatal 'Missing required argument to _extract_()!' + [[ $# -lt 1 ]] && fatal 'Missing required argument to _extract_()!' - [[ "${2:-}" == "v" ]] && vv="v" + [[ ${2:-} == "v" ]] && vv="v" - if [ -f "$1" ]; then - case "$1" in - *.tar.bz2 | *.tbz | *.tbz2) tar "x${vv}jf" "$1" ;; - *.tar.gz | *.tgz) tar "x${vv}zf" "$1" ;; - *.tar.xz) - xz --decompress "$1" - set -- "$@" "${1:0:-3}" - ;; - *.tar.Z) - uncompress "$1" - set -- "$@" "${1:0:-2}" - ;; - *.bz2) bunzip2 "$1" ;; - *.deb) dpkg-deb -x${vv} "$1" "${1:0:-4}" ;; - *.pax.gz) - gunzip "$1" - set -- "$@" "${1:0:-3}" - ;; - *.gz) gunzip "$1" ;; - *.pax) pax -r -f "$1" ;; - *.pkg) pkgutil --expand "$1" "${1:0:-4}" ;; - *.rar) unrar x "$1" ;; - *.rpm) rpm2cpio "$1" | cpio -idm${vv} ;; - *.tar) tar "x${vv}f" "$1" ;; - *.txz) - mv "$1" "${1:0:-4}.tar.xz" - set -- "$@" "${1:0:-4}.tar.xz" - ;; - *.xz) xz --decompress "$1" ;; - *.zip | *.war | *.jar) unzip "$1" ;; - *.Z) uncompress "$1" ;; - *.7z) 7za x "$1" ;; - *) return 1 ;; - esac - else - return 1 - fi - shift + if [ -f "$1" ]; then + case "$1" in + *.tar.bz2 | *.tbz | *.tbz2) tar "x${vv}jf" "$1" ;; + *.tar.gz | *.tgz) tar "x${vv}zf" "$1" ;; + *.tar.xz) + xz --decompress "$1" + set -- "$@" "${1:0:-3}" + ;; + *.tar.Z) + uncompress "$1" + set -- "$@" "${1:0:-2}" + ;; + *.bz2) bunzip2 "$1" ;; + *.deb) dpkg-deb -x${vv} "$1" "${1:0:-4}" ;; + *.pax.gz) + gunzip "$1" + set -- "$@" "${1:0:-3}" + ;; + *.gz) gunzip "$1" ;; + *.pax) pax -r -f "$1" ;; + *.pkg) pkgutil --expand "$1" "${1:0:-4}" ;; + *.rar) unrar x "$1" ;; + *.rpm) rpm2cpio "$1" | cpio -idm${vv} ;; + *.tar) tar "x${vv}f" "$1" ;; + *.txz) + mv "$1" "${1:0:-4}.tar.xz" + set -- "$@" "${1:0:-4}.tar.xz" + ;; + *.xz) xz --decompress "$1" ;; + *.zip | *.war | *.jar) unzip "$1" ;; + *.Z) uncompress "$1" ;; + *.7z) 7za x "$1" ;; + *) return 1 ;; + esac + else + return 1 + fi + shift } _json2yaml_() { - # DESC: Convert JSON to YAML - # ARGS: $1 (Required) - JSON file - # OUTS: None + # DESC: Convert JSON to YAML + # ARGS: $1 (Required) - JSON file + # OUTS: None - python -c 'import sys, yaml, json; yaml.safe_dump(json.load(sys.stdin), sys.stdout, default_flow_style=False)' <"${1:?_json2yaml_ needs a file}" + python -c 'import sys, yaml, json; yaml.safe_dump(json.load(sys.stdin), sys.stdout, default_flow_style=False)' <"${1:?_json2yaml_ needs a file}" } _makeSymlink_() { - # DESC: Creates a symlink and backs up a file which may be overwritten by the new symlink. If the - # exact same symlink already exists, nothing is done. - # Default behavior will create a backup of a file to be overwritten - # ARGS: $1 (Required) - Source file - # $2 (Required) - Destination - # $3 (Optional) - Backup directory for files which may be overwritten (defaults to 'backup') - # OPTS: -n - Do not create a backup if target already exists - # -s - Use sudo when removing old files to make way for new symlinks - # OUTS: None - # USAGE: _makeSymlink_ "/dir/someExistingFile" "/dir/aNewSymLink" "/dir/backup/location" - # NOTE: This function makes use of the _execute_ function + # DESC: Creates a symlink and backs up a file which may be overwritten by the new symlink. If the + # exact same symlink already exists, nothing is done. + # Default behavior will create a backup of a file to be overwritten + # ARGS: $1 (Required) - Source file + # $2 (Required) - Destination + # $3 (Optional) - Backup directory for files which may be overwritten (defaults to 'backup') + # OPTS: -n - Do not create a backup if target already exists + # -s - Use sudo when removing old files to make way for new symlinks + # OUTS: None + # USAGE: _makeSymlink_ "/dir/someExistingFile" "/dir/aNewSymLink" "/dir/backup/location" + # NOTE: This function makes use of the _execute_ function - local opt - local OPTIND=1 - local backupOriginal=true - local useSudo=false + local opt + local OPTIND=1 + local backupOriginal=true + local useSudo=false - while getopts ":nNsS" opt; do - case $opt in - n | N) backupOriginal=false ;; - s | S) useSudo=true ;; - *) - { - error "Unrecognized option '$1' passed to _makeSymlink_" "$LINENO" - return 1 + while getopts ":nNsS" opt; do + case $opt in + n | N) backupOriginal=false ;; + s | S) useSudo=true ;; + *) + { + error "Unrecognized option '$1' passed to _makeSymlink_" "$LINENO" + return 1 + } + ;; + esac + done + shift $((OPTIND - 1)) + + if ! command -v realpath >/dev/null 2>&1; then + error "We must have 'realpath' installed and available in \$PATH to run." + if [[ $OSTYPE == "darwin"* ]]; then + notice "Install coreutils using homebrew and rerun this script." + info "\t$ brew install coreutils" + fi + _safeExit_ 1 + fi + + [[ $# -lt 2 ]] && fatal 'Missing required argument to _makeSymlink_()!' + + local s="$1" + local d="$2" + local b="${3:-}" + local o + + # Fix files where $HOME is written as '~' + d="${d/\~/$HOME}" + s="${s/\~/$HOME}" + b="${b/\~/$HOME}" + + [ ! -e "$s" ] \ + && { + error "'$s' not found" + return 1 + } + [ -z "$d" ] \ + && { + error "'${d}' not specified" + return 1 + } + [ ! "$(declare -f "_execute_")" ] \ + && { + echo "need function _execute_" + return 1 + } + [ ! "$(declare -f "_backupFile_")" ] \ + && { + echo "need function _backupFile_" + return 1 } - ;; - esac - done - shift $((OPTIND - 1)) - if ! command -v realpath >/dev/null 2>&1; then - error "We must have 'realpath' installed and available in \$PATH to run." - if [[ "$OSTYPE" == "darwin"* ]]; then - notice "Install coreutils using homebrew and rerun this script." - info "\t$ brew install coreutils" + # Create destination directory if needed + [ ! -d "${d%/*}" ] \ + && _execute_ "mkdir -p \"${d%/*}\"" + + if [ ! -e "${d}" ]; then + _execute_ "ln -fs \"${s}\" \"${d}\"" "symlink ${s} → ${d}" + elif [ -h "${d}" ]; then + o="$(realpath "${d}")" + + [[ ${o} == "${s}" ]] && { + if [ "${DRYRUN}" == true ]; then + dryrun "Symlink already exists: ${s} → ${d}" + else + info "Symlink already exists: ${s} → ${d}" + fi + return 0 + } + + if [[ ${backupOriginal} == true ]]; then + _backupFile_ "${d}" "${b:-backup}" + fi + if [[ ${DRYRUN} == false ]]; then + if [[ ${useSudo} == true ]]; then + command rm -rf "${d}" + else + command rm -rf "${d}" + fi + fi + _execute_ "ln -fs \"${s}\" \"${d}\"" "symlink ${s} → ${d}" + elif [ -e "${d}" ]; then + if [[ ${backupOriginal} == true ]]; then + _backupFile_ "${d}" "${b:-backup}" + fi + if [[ ${DRYRUN} == false ]]; then + if [[ ${useSudo} == true ]]; then + sudo command rm -rf "${d}" + else + command rm -rf "${d}" + fi + fi + _execute_ "ln -fs \"${s}\" \"${d}\"" "symlink ${s} → ${d}" + else + warning "Error linking: ${s} → ${d}" + return 1 fi - _safeExit_ 1 - fi - - [[ $# -lt 2 ]] && fatal 'Missing required argument to _makeSymlink_()!' - - local s="$1" - local d="$2" - local b="${3:-}" - local o - - # Fix files where $HOME is written as '~' - d="${d/\~/$HOME}" - s="${s/\~/$HOME}" - b="${b/\~/$HOME}" - - [ ! -e "$s" ] \ - && { - error "'$s' not found" - return 1 - } - [ -z "$d" ] \ - && { - error "'${d}' not specified" - return 1 - } - [ ! "$(declare -f "_execute_")" ] \ - && { - echo "need function _execute_" - return 1 - } - [ ! "$(declare -f "_backupFile_")" ] \ - && { - echo "need function _backupFile_" - return 1 - } - - # Create destination directory if needed - [ ! -d "${d%/*}" ] \ - && _execute_ "mkdir -p \"${d%/*}\"" - - if [ ! -e "${d}" ]; then - _execute_ "ln -fs \"${s}\" \"${d}\"" "symlink ${s} → ${d}" - elif [ -h "${d}" ]; then - o="$(realpath "${d}")" - - [[ "${o}" == "${s}" ]] && { - if [ "${DRYRUN}" == true ]; then - dryrun "Symlink already exists: ${s} → ${d}" - else - info "Symlink already exists: ${s} → ${d}" - fi - return 0 - } - - if [[ "${backupOriginal}" == true ]]; then - _backupFile_ "${d}" "${b:-backup}" - fi - if [[ "${DRYRUN}" == false ]]; then - if [[ "${useSudo}" == true ]]; then - command rm -rf "${d}" - else - command rm -rf "${d}" - fi - fi - _execute_ "ln -fs \"${s}\" \"${d}\"" "symlink ${s} → ${d}" - elif [ -e "${d}" ]; then - if [[ "${backupOriginal}" == true ]]; then - _backupFile_ "${d}" "${b:-backup}" - fi - if [[ "${DRYRUN}" == false ]]; then - if [[ "${useSudo}" == true ]]; then - sudo command rm -rf "${d}" - else - command rm -rf "${d}" - fi - fi - _execute_ "ln -fs \"${s}\" \"${d}\"" "symlink ${s} → ${d}" - else - warning "Error linking: ${s} → ${d}" - return 1 - fi - return 0 + return 0 } _parseYAML_() { - # DESC: Convert a YANML file into BASH variables for use in a shell script - # ARGS: $1 (Required) - Source YAML file - # $2 (Required) - Prefix for the variables to avoid namespace collisions - # OUTS: Prints variables and arrays derived from YAML File - # USAGE: To source into a script - # _parseYAML_ "sample.yml" "CONF_" > tmp/variables.txt - # source "tmp/variables.txt" - # - # NOTE: https://gist.github.com/DinoChiesa/3e3c3866b51290f31243 - # https://gist.github.com/epiloque/8cf512c6d64641bde388 + # DESC: Convert a YANML file into BASH variables for use in a shell script + # ARGS: $1 (Required) - Source YAML file + # $2 (Required) - Prefix for the variables to avoid namespace collisions + # OUTS: Prints variables and arrays derived from YAML File + # USAGE: To source into a script + # _parseYAML_ "sample.yml" "CONF_" > tmp/variables.txt + # source "tmp/variables.txt" + # + # NOTE: https://gist.github.com/DinoChiesa/3e3c3866b51290f31243 + # https://gist.github.com/epiloque/8cf512c6d64641bde388 - local yamlFile="${1:?_parseYAML_ needs a file}" - local prefix="${2:-}" + local yamlFile="${1:?_parseYAML_ needs a file}" + local prefix="${2:-}" - [ ! -s "${yamlFile}" ] && return 1 + [ ! -s "${yamlFile}" ] && return 1 - local s='[[:space:]]*' - local w='[a-zA-Z0-9_]*' - local fs="$(echo @ | tr @ '\034')" - sed -ne "s|^\(${s}\)\(${w}\)${s}:${s}\"\(.*\)\"${s}\$|\1${fs}\2${fs}\3|p" \ - -e "s|^\(${s}\)\(${w}\)${s}[:-]${s}\(.*\)${s}\$|\1${fs}\2${fs}\3|p" "${yamlFile}" \ - | awk -F"${fs}" '{ + local s='[[:space:]]*' + local w='[a-zA-Z0-9_]*' + local fs="$(echo @ | tr @ '\034')" + sed -ne "s|^\(${s}\)\(${w}\)${s}:${s}\"\(.*\)\"${s}\$|\1${fs}\2${fs}\3|p" \ + -e "s|^\(${s}\)\(${w}\)${s}[:-]${s}\(.*\)${s}\$|\1${fs}\2${fs}\3|p" "${yamlFile}" \ + | awk -F"${fs}" '{ indent = length($1)/2; if (length($2) == 0) { conj[indent]="+";} else {conj[indent]="";} vname[indent] = $2; @@ -481,101 +480,101 @@ _parseYAML_() { } _readFile_() { - # DESC: Prints each line of a file - # ARGS: $1 (Required) - Input file - # OUTS: Prints contents of file + # DESC: Prints each line of a file + # ARGS: $1 (Required) - Input file + # OUTS: Prints contents of file - [[ $# -lt 1 ]] && fatal 'Missing required argument to _readFile_()!' + [[ $# -lt 1 ]] && fatal 'Missing required argument to _readFile_()!' - local result - local c="$1" + local result + local c="$1" - [ ! -f "$c" ] \ - && { - echo "'$c' not found" - return 1 - } + [ ! -f "$c" ] \ + && { + echo "'$c' not found" + return 1 + } - while read -r result; do - echo "${result}" - done <"${c}" + while read -r result; do + echo "${result}" + done <"${c}" } _sourceFile_() { - # DESC: Source a file into a script - # ARGS: $1 (Required) - File to be sourced - # OUTS: None + # DESC: Source a file into a script + # ARGS: $1 (Required) - File to be sourced + # OUTS: None - [[ $# -lt 1 ]] && fatal 'Missing required argument to _sourceFile_()!' + [[ $# -lt 1 ]] && fatal 'Missing required argument to _sourceFile_()!' - local c="$1" + local c="$1" - [ ! -f "$c" ] \ - && { - fatal "Attempted to source '$c'. Not found" - return 1 - } + [ ! -f "${c}" ] \ + && { + fatal "Attempted to source '$c'. Not found" + return 1 + } - source "$c" - return 0 + source "${c}" + return 0 } _uniqueFileName_() { - # DESC: Ensure a file to be created has a unique filename to avoid overwriting other files - # ARGS: $1 (Required) - Name of file to be created - # $2 (Optional) - Separation characted (Defaults to a period '.') - # OUTS: Prints unique filename to STDOUT - # USAGE: _uniqueFileName_ "/some/dir/file.txt" "-" + # DESC: Ensure a file to be created has a unique filename to avoid overwriting other files + # ARGS: $1 (Required) - Name of file to be created + # $2 (Optional) - Separation characted (Defaults to a period '.') + # OUTS: Prints unique filename to STDOUT + # USAGE: _uniqueFileName_ "/some/dir/file.txt" "-" - local fullfile="${1:?_uniqueFileName_ needs a file}" - local spacer="${2:-.}" - local directory - local filename - local extension - local newfile - local n + local fullfile="${1:?_uniqueFileName_ needs a file}" + local spacer="${2:-.}" + local directory + local filename + local extension + local newfile + local n - if ! command -v realpath >/dev/null 2>&1; then - error "We must have 'realpath' installed and available in \$PATH to run." - if [[ "$OSTYPE" == "darwin"* ]]; then - notice "Install coreutils using homebrew and rerun this script." - info "\t$ brew install coreutils" + if ! command -v realpath >/dev/null 2>&1; then + error "We must have 'realpath' installed and available in \$PATH to run." + if [[ $OSTYPE == "darwin"* ]]; then + notice "Install coreutils using homebrew and rerun this script." + info "\t$ brew install coreutils" + fi + _safeExit_ 1 fi - _safeExit_ 1 - fi - # Find directories with realpath if input is an actual file - if [ -e "${fullfile}" ]; then - fullfile="$(realpath "${fullfile}")" - fi + # Find directories with realpath if input is an actual file + if [ -e "${fullfile}" ]; then + fullfile="$(realpath "${fullfile}")" + fi - directory="$(dirname "${fullfile}")" - filename="$(basename "${fullfile}")" + directory="$(dirname "${fullfile}")" + filename="$(basename "${fullfile}")" - # Extract extensions only when they exist - if [[ "${filename}" =~ \.[a-zA-Z]{2,4}$ ]]; then - extension=".${filename##*.}" - filename="${filename%.*}" - fi + # Extract extensions only when they exist + if [[ ${filename} =~ \.[a-zA-Z]{2,4}$ ]]; then + extension=".${filename##*.}" + filename="${filename%.*}" + fi - newfile="${directory}/${filename}${extension:-}" + newfile="${directory}/${filename}${extension:-}" - if [ -e "${newfile}" ]; then - n=1 - while [[ -e "${directory}/${filename}${extension:-}${spacer}${n}" ]]; do - ((n++)) - done - newfile="${directory}/${filename}${extension:-}${spacer}${n}" - fi + if [ -e "${newfile}" ]; then + n=1 + while [[ -e "${directory}/${filename}${extension:-}${spacer}${n}" ]]; do + ((n++)) + done + newfile="${directory}/${filename}${extension:-}${spacer}${n}" + fi - echo "${newfile}" - return 0 + echo "${newfile}" + return 0 } _yaml2json_() { - # DESC: Convert a YAML file to JSON - # ARGS: $1 (Required) - Input YAML file - # OUTS: None + # DESC: Convert a YAML file to JSON + # ARGS: $1 (Required) - Input YAML file + # OUTS: None - python -c 'import sys, yaml, json; json.dump(yaml.load(sys.stdin), sys.stdout, indent=4)' <"${1:?_yaml2json_ needs a file}" + python -c 'import sys, yaml, json; json.dump(yaml.load(sys.stdin), sys.stdout, indent=4)' <"${1:?_yaml2json_ needs a file}" } diff --git a/utilities/macOS.bash b/utilities/macOS.bash index 20f4391..35e40c9 100644 --- a/utilities/macOS.bash +++ b/utilities/macOS.bash @@ -1,39 +1,39 @@ # 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: true/false - 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 - return 0 - else - return 1 - fi + if [[ (${finder_pid} -gt 1) && (${STY-} == "") ]]; then + return 0 + else + return 1 + fi } _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 - if _haveScriptableFinder_; then - guiPrompt="${1:-Password:}" - guiInput=$( - osascript &>/dev/null </dev/null <