mirror of
https://github.com/natelandau/shell-scripting-templates.git
synced 2025-11-08 05:03:46 -05:00
Squashed commit of the following:
commit 61bf734812cb62ba6e0ec224bc15f7928705a8a2 Author: Nathaniel Landau <nate@natelandau.com> Date: Thu Oct 21 15:44:21 2021 -0400 Major overhaul continued - rename templates - add checks utilities - add new array utilities - rename files - add assorted utilities - improve documentation commit 546178fff3b526f492eb0eeffc63f79537e75de3 Author: Nathaniel Landau <nate@natelandau.com> Date: Wed Oct 20 16:31:14 2021 -0400 Update conventions commit f6d0642f85518efda9c5d8472b99d1c14163e381 Author: Nathaniel Landau <nate@natelandau.com> Date: Wed Oct 20 09:47:09 2021 -0400 minor formatting changes commit 2217612b55e3f9faf803a2d0c937ea2261206505 Author: Nathaniel Landau <nate@natelandau.com> Date: Tue Oct 19 17:59:09 2021 -0400 add new functions commit 347ba7aa738dcd6a5ad9d70886b38da3a17dc89e Author: Nathaniel Landau <nate@natelandau.com> Date: Tue Oct 19 12:06:44 2021 -0400 major overhaul - Add standaloneTemplate.sh - Rework README - Refactor inline documentation - Enforce coding standards - Remove CSV utilities - Add new array utilities - add _useGNUutils_ - more ... commit cd8e0d49aef25eeaf6b3e71a3c9e1f29ab9b06f5 Author: Nathaniel Landau <nate@natelandau.com> Date: Sun Oct 17 09:56:08 2021 -0400 Add debug functions commit f7c5c0a3d19815dcc6ba80b5f5a2ebb77ef88b07 Author: Nathaniel Landau <nate@natelandau.com> Date: Sat Oct 16 21:10:01 2021 -0400 add new array functions _joinArray_, _isEmptyArray_, _sortArray_, _reverseSortArray_, and _mergearrays_ commit d8bc3d8cabdbcee3c479f97b43a45bdfe3bdafe0 Author: Nathaniel Landau <nate@natelandau.com> Date: Fri Oct 15 17:27:12 2021 -0400 add _columnize_ commit 2fd2ae9435f476bc3968c3eb0d793db4bf1d9eaf Author: Nathaniel Landau <nate@natelandau.com> Date: Mon Oct 11 22:17:45 2021 -0400 _progressBar_: Fix unbound variable commit e8933d15fc955a1acc665e9a081f131e681855d5 Author: Nathaniel Landau <nate@natelandau.com> Date: Sun Oct 10 11:50:42 2021 -0400 _alert_: header now underlined commit c9ce894361dec7d3513c038794a155519baf26bc Author: Nathaniel Landau <nate@natelandau.com> Date: Tue Oct 5 09:49:42 2021 -0400 _alert_: line numbers to gray commit 4aaddd336ce613f629a7e6a62ef3b27ffc24d22d Author: Nathaniel Landau <nate@natelandau.com> Date: Fri Oct 8 15:05:20 2021 -0400 _usage_ to stdout commit e2372fc3122ec1f20acc27f04d29b3785f014e25 Author: Nathaniel Landau <nate@natelandau.com> Date: Tue Oct 5 09:38:26 2021 -0400 _setPATH_: remove unneeded logic commit e60c75b6c954ac4bd146e2758252168027b9a43d Author: Nathaniel Landau <nate@natelandau.com> Date: Tue Oct 5 09:25:38 2021 -0400 _findSource_: bugfix commit 0e84912e1ccd7203e5beff9f8737f8374f4aa5d8 Author: Nathaniel Landau <nate@natelandau.com> Date: Thu Sep 30 16:29:25 2021 -0400 add requirements to documentation commit 2c24843e3ada591e1868a94416e40b5ac0aa4994 Author: Nathaniel Landau <nate@natelandau.com> Date: Thu Sep 30 15:34:10 2021 -0400 _uniqueFilename_: improve extension handling commit 08bc2dfdcc8632efee9179e9c960a574fc17cf0c Author: Nathaniel Landau <nate@natelandau.com> Date: Mon Sep 27 15:13:53 2021 -0400 improve hooks script commit 641918f1559d3b3aa38a9bbdf418938b2b81c176 Author: Nathaniel Landau <nate@natelandau.com> Date: Fri Sep 24 08:16:52 2021 -0400 _inArry_: case insensitivity commit eae10f170680540fdb4a1222add7e54f8785ea63 Author: Nathaniel Landau <nate@natelandau.com> Date: Mon Sep 20 18:31:44 2021 -0400 clean up alerting commit 700acd56f57fd57db84ef0e232ef41cdd7aee43c Author: Nathaniel Landau <nate@natelandau.com> Date: Mon Sep 20 18:22:11 2021 -0400 refactor _execute_ commit d893f86900a9fed9d91a0c9cc06c13b6b34d9926 Author: Nathaniel Landau <nate@natelandau.com> Date: Mon Sep 20 18:19:18 2021 -0400 'fatal' replaces 'die' commit 3326857bf127bef36cd9982246aa5b826d796d0a Author: Nathaniel Landau <nate@natelandau.com> Date: Fri Sep 17 08:29:50 2021 -0400 _execute_: ensure quiet and verbose work together
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
scratch
|
||||||
|
tmp
|
||||||
|
*.DS_Store
|
||||||
|
.cache
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
This folder contains git hook scripts which will be executed on the client side before/after certain git actions are completed.
|
This folder contains a git pre-commit script which will be executed on the client side before files are committed to the repository. This script provides automated linting and testing of multiple file types.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
To install these hooks, create a symlink to `/path/to/repo/.git/hooks` directory.
|
|
||||||
|
|
||||||
|
To install the hook, create a symlink into the `/path/to/repo/.git/hooks` directory.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ln -s "$(git rev-parse --show-toplevel)/.hooks/pre-commit.sh" "$(git rev-parse --show-toplevel)/.git/hooks/pre-commit"
|
ln -s "$(git rev-parse --show-toplevel)/.hooks/pre-commit.sh" "$(git rev-parse --show-toplevel)/.git/hooks/pre-commit"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ _mainScript_() {
|
|||||||
STOP_WORD_FILE="${HOME}/.git_stop_words"
|
STOP_WORD_FILE="${HOME}/.git_stop_words"
|
||||||
GIT_DIFF_TEMP="${TMP_DIR}/diff.txt"
|
GIT_DIFF_TEMP="${TMP_DIR}/diff.txt"
|
||||||
|
|
||||||
if cat "${STOP_WORD_FILE}" | grep . | grep -v '# ' >"${TMP_DIR}/pattern_file.txt"; then
|
if [ -f "${STOP_WORD_FILE}" ]; then
|
||||||
|
|
||||||
if [[ $(basename "${STOP_WORD_FILE}") == "$(basename "${1}")" ]]; then
|
if [[ $(basename "${STOP_WORD_FILE}") == "$(basename "${1}")" ]]; then
|
||||||
debug "Don't check stop words file for stop words. Skipping $(basename "${1}")"
|
debug "Don't check stop words file for stop words. Skipping $(basename "${1}")"
|
||||||
@@ -25,16 +25,18 @@ _mainScript_() {
|
|||||||
fi
|
fi
|
||||||
debug "Checking for stop words"
|
debug "Checking for stop words"
|
||||||
|
|
||||||
# remove blank lines and comments from stopwords file
|
# remove blank lines from stopwords file
|
||||||
|
cat "${STOP_WORD_FILE}" | sed '/^$/d' >"${TMP_DIR}/pattern_file.txt"
|
||||||
|
|
||||||
# Add diff to a temporary file
|
# Add diff to a temporary file
|
||||||
git diff --cached -- "${1}" | grep '^+' >"${GIT_DIFF_TEMP}"
|
git diff --cached -- "${1}" | grep '^+' >"${GIT_DIFF_TEMP}"
|
||||||
|
|
||||||
if grep --file="${TMP_DIR}/pattern_file.txt" "${GIT_DIFF_TEMP}"; then
|
if grep --file="${TMP_DIR}/pattern_file.txt" "${GIT_DIFF_TEMP}"; then
|
||||||
error "Found git stop word in '$(basename "${1}")'"
|
error "Found git stop word in '$(basename "${1}")'"
|
||||||
_safeExit_ 1
|
_safeExit_ 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
debug "Could not find git stopwords file expected at '${STOP_WORD_FILE}'. Or it was empty. Continuing..."
|
debug "Could not find git stopwords file expected at '${STOP_WORD_FILE}'. Continuing..."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,26 +89,35 @@ _mainScript_() {
|
|||||||
error "Error in ${1}"
|
error "Error in ${1}"
|
||||||
_safeExit_ 1
|
_safeExit_ 1
|
||||||
else
|
else
|
||||||
success "yaml-lint passed: '${1}'"
|
success "yaml-lint passed: '${1}'"
|
||||||
fi
|
fi
|
||||||
elif command -v yamllint >/dev/null; then
|
elif command -v yamllint >/dev/null; then
|
||||||
debug "Linting YAML File"
|
debug "Linting YAML File"
|
||||||
if ! yamllint "${1}"; then
|
if [ -f "$(git rev-parse --show-toplevel)/.yamllint.yml" ]; then
|
||||||
error "Error in ${1}"
|
if ! yamllint -c "$(git rev-parse --show-toplevel)/.yamllint.yml" "${1}"; then
|
||||||
_safeExit_ 1
|
error "YAML Error in ${1}"
|
||||||
else
|
_safeExit_ 1
|
||||||
|
else
|
||||||
success "yamllint passed: '${1}'"
|
success "yamllint passed: '${1}'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if ! yamllint "${1}"; then
|
||||||
|
error "YAML Error in ${1}"
|
||||||
|
_safeExit_ 1
|
||||||
|
else
|
||||||
|
success "yamllint passed: '${1}'"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
notice "No YAML linter installed. Continuing..."
|
notice "No YAML linter installed. Continuiing..."
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_lintShellscripts_() {
|
_lintShellscripts_() {
|
||||||
if command -v shellcheck >/dev/null; then
|
if command -v shellcheck >/dev/null; then
|
||||||
debug "Linting shellscript: ${1}"
|
debug "Linting shellscript: ${1}"
|
||||||
if ! shellcheck --exclude=2016,2059,2001,2002,2148,1090,2162,2005,2034,2154,2086,2155,2181,2164,2120,2119,1083,1117,2207 "${1}"; then
|
if ! shellcheck --exclude=2016,2059,2001,2002,2148,1090,2162,2005,2034,2154,2086,2155,2181,2164,2120,2119,1083,1117,2207,1091 "${1}"; then
|
||||||
error "Error in ${file}"
|
error "Error in ${1}"
|
||||||
_safeExit_ 1
|
_safeExit_ 1
|
||||||
else
|
else
|
||||||
success "shellcheck passed: '${1}'"
|
success "shellcheck passed: '${1}'"
|
||||||
@@ -133,7 +144,47 @@ _mainScript_() {
|
|||||||
unset filename
|
unset filename
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lintAnsible_() {
|
||||||
|
|
||||||
|
if ! command -v ansible-lint >/dev/null; then
|
||||||
|
notice "Found Ansible files but ansible-lint is not available. Continuing..."
|
||||||
|
return 0
|
||||||
|
elif [[ "$(basename ${1})" =~ (^\.|^requirements|j2|vault\.yml|variables|meta|defaults?|inventory) ]]; then
|
||||||
|
# Don't lint files that are not Ansible playbooks
|
||||||
|
debug "won't ansible lint: ${1}"
|
||||||
|
return 0
|
||||||
|
elif [[ ${1} =~ /(handlers|vars/|defaults/|meta/|molecule/|templates/|files/)/ ]]; then
|
||||||
|
# Don't lint in directory names that are not likely to contain Ansible playbooks
|
||||||
|
debug "Won't ansible lint: ${1}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ANSIBLE_COMMAND="ansible-lint -vv --parseable-severity"
|
||||||
|
if [ -f "$(git rev-parse --show-toplevel)/.ansible-lint.yml" ]; then
|
||||||
|
ANSIBLE_COMMAND="ansible-lint -p -c $(git rev-parse --show-toplevel)/.ansible-lint.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
debug "Linting ansible file: ${1}"
|
||||||
|
if ! ${ANSIBLE_COMMAND} "${1}"; then
|
||||||
|
error "Ansible-lint error"
|
||||||
|
_safeExit_ 1
|
||||||
|
else
|
||||||
|
success "ansible-lint passed: ${1}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# RUN SCRIPT LOGIC
|
# RUN SCRIPT LOGIC
|
||||||
|
|
||||||
|
# Attempt to discern if we are working on an repo that contains ansible files
|
||||||
|
IS_ANSIBLE_REPO=false
|
||||||
|
if find "$(git rev-parse --show-toplevel)" -type f -mindepth 1 -maxdepth 1 \
|
||||||
|
-name "inventory.yml" \
|
||||||
|
-o -name "ansible.cfg" \
|
||||||
|
-o -name ".ansible-lint.yml" &>/dev/null; then
|
||||||
|
|
||||||
|
IS_ANSIBLE_REPO=true
|
||||||
|
fi
|
||||||
|
|
||||||
_ignoreSymlinks_
|
_ignoreSymlinks_
|
||||||
|
|
||||||
while read -r STAGED_FILE; do
|
while read -r STAGED_FILE; do
|
||||||
@@ -142,17 +193,18 @@ _mainScript_() {
|
|||||||
|
|
||||||
_gitStopWords_ "${STAGED_FILE}"
|
_gitStopWords_ "${STAGED_FILE}"
|
||||||
|
|
||||||
if [[ "${STAGED_FILE}" =~ \.(yaml|yml)$ ]]; then
|
if [[ ${STAGED_FILE} =~ \.(yaml|yml)$ ]]; then
|
||||||
_lintYAML_ "${STAGED_FILE}"
|
_lintYAML_ "${STAGED_FILE}"
|
||||||
|
if [ "${IS_ANSIBLE_REPO}" = true ]; then
|
||||||
|
_lintAnsible_ "${STAGED_FILE}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ "${STAGED_FILE}" =~ \.(bash|sh)$ ]]; then
|
if [[ ${STAGED_FILE} =~ \.(bash|sh)$ || "$(head -n 1 "${STAGED_FILE}")" =~ ^#!.*bash$ ]]; then
|
||||||
_lintShellscripts_ "${STAGED_FILE}"
|
_lintShellscripts_ "${STAGED_FILE}"
|
||||||
fi
|
fi
|
||||||
if [[ "${STAGED_FILE}" =~ \.(sh|bash|bats|zsh)$ ]]; then
|
if [[ ${STAGED_FILE} =~ \.(sh|bash|bats|zsh)$ || "$(head -n 1 "${STAGED_FILE}")" =~ ^#!.*bash$ ]]; then
|
||||||
_BATS_ "${STAGED_FILE}"
|
_BATS_ "${STAGED_FILE}"
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
fatal "${STAGED_FILE} does not exist"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done < <(git diff --cached --name-only --line-prefix="$(git rev-parse --show-toplevel)/")
|
done < <(git diff --cached --name-only --line-prefix="$(git rev-parse --show-toplevel)/")
|
||||||
@@ -160,22 +212,22 @@ _mainScript_() {
|
|||||||
} # end _mainScript_
|
} # end _mainScript_
|
||||||
|
|
||||||
# ################################## Flags and defaults
|
# ################################## Flags and defaults
|
||||||
# Script specific
|
# Script specific
|
||||||
|
|
||||||
# Common
|
# Common
|
||||||
LOGFILE="${HOME}/logs/$(basename "$0").log"
|
LOGFILE="${HOME}/logs/$(basename "$0").log"
|
||||||
QUIET=false
|
QUIET=false
|
||||||
LOGLEVEL=ERROR
|
LOGLEVEL=ERROR
|
||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
FORCE=false
|
FORCE=false
|
||||||
DRYRUN=false
|
DRYRUN=false
|
||||||
declare -a ARGS=()
|
declare -a ARGS=()
|
||||||
NOW=$(LC_ALL=C date +"%m-%d-%Y %r") # Returns: 06-14-2015 10:34:40 PM
|
NOW=$(LC_ALL=C date +"%m-%d-%Y %r") # Returns: 06-14-2015 10:34:40 PM
|
||||||
DATESTAMP=$(LC_ALL=C date +%Y-%m-%d) # Returns: 2015-06-14
|
DATESTAMP=$(LC_ALL=C date +%Y-%m-%d) # Returns: 2015-06-14
|
||||||
HOURSTAMP=$(LC_ALL=C date +%r) # Returns: 10:34:40 PM
|
HOURSTAMP=$(LC_ALL=C date +%r) # Returns: 10:34:40 PM
|
||||||
TIMESTAMP=$(LC_ALL=C date +%Y%m%d_%H%M%S) # Returns: 20150614_223440
|
TIMESTAMP=$(LC_ALL=C date +%Y%m%d_%H%M%S) # Returns: 20150614_223440
|
||||||
LONGDATE=$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z") # Returns: Sun, 10 Jan 2016 20:47:53 -0500
|
LONGDATE=$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z") # Returns: Sun, 10 Jan 2016 20:47:53 -0500
|
||||||
GMTDATE=$(LC_ALL=C date -u -R | sed 's/\+0000/GMT/') # Returns: Wed, 13 Jan 2016 15:55:29 GMT
|
GMTDATE=$(LC_ALL=C date -u -R | sed 's/\+0000/GMT/') # Returns: Wed, 13 Jan 2016 15:55:29 GMT
|
||||||
|
|
||||||
# ################################## Custom utility functions
|
# ################################## Custom utility functions
|
||||||
_setPATH_() {
|
_setPATH_() {
|
||||||
@@ -190,37 +242,65 @@ _setPATH_() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
for NEWPATH in "${NEWPATHS[@]}"; do
|
for NEWPATH in "${NEWPATHS[@]}"; do
|
||||||
if ! echo "$PATH" | grep -Eq "(^|:)${NEWPATH}($|:)"; then
|
if [ -d "${NEWPATH}" ]; then
|
||||||
PATH="${NEWPATH}:${PATH}"
|
if ! echo "${PATH}" | grep -Eq "(^|:)${NEWPATH}($|:)"; then
|
||||||
debug "Added '${tan}${NEWPATH}${purple}' to PATH"
|
PATH="${NEWPATH}:${PATH}"
|
||||||
|
debug "Added '${NEWPATH}' to PATH"
|
||||||
|
else
|
||||||
|
debug "_setPATH_: '${NEWPATH}' already exists in PATH"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
debug "_setPATH_: can not find: ${NEWPATH}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
# ################################## Common Functions for script template
|
# ################################## Common Functions for script template
|
||||||
# Colors
|
_setColors_() {
|
||||||
if tput setaf 1 &>/dev/null; then
|
# DESC: Sets colors use for alerts.
|
||||||
bold=$(tput bold)
|
# ARGS: None
|
||||||
white=$(tput setaf 7)
|
# OUTS: None
|
||||||
reset=$(tput sgr0)
|
# USAGE: echo "${blue}Some text${reset}"
|
||||||
purple=$(tput setaf 171)
|
|
||||||
red=$(tput setaf 1)
|
if tput setaf 1 &>/dev/null; then
|
||||||
green=$(tput setaf 76)
|
bold=$(tput bold)
|
||||||
tan=$(tput setaf 3)
|
underline=$(tput smul)
|
||||||
yellow=$(tput setaf 3)
|
reverse=$(tput rev)
|
||||||
blue=$(tput setaf 38)
|
reset=$(tput sgr0)
|
||||||
underline=$(tput sgr 0 1)
|
|
||||||
else
|
if [[ $(tput colors) -ge 256 ]] 2>/dev/null; then
|
||||||
bold="\033[4;37m"
|
white=$(tput setaf 231)
|
||||||
white="\033[0;37m"
|
blue=$(tput setaf 38)
|
||||||
reset="\033[0m"
|
yellow=$(tput setaf 11)
|
||||||
purple="\033[0;35m"
|
tan=$(tput setaf 3)
|
||||||
red="\033[0;31m"
|
green=$(tput setaf 82)
|
||||||
green="\033[1;32m"
|
red=$(tput setaf 1)
|
||||||
tan="\033[0;33m"
|
purple=$(tput setaf 171)
|
||||||
yellow="\033[0;33m"
|
gray=$(tput setaf 250)
|
||||||
blue="\033[0;34m"
|
else
|
||||||
underline="\033[4;37m"
|
white=$(tput setaf 7)
|
||||||
fi
|
blue=$(tput setaf 38)
|
||||||
|
yellow=$(tput setaf 3)
|
||||||
|
tan=$(tput setaf 3)
|
||||||
|
green=$(tput setaf 2)
|
||||||
|
red=$(tput setaf 1)
|
||||||
|
purple=$(tput setaf 13)
|
||||||
|
gray=$(tput setaf 7)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bold="\033[4;37m"
|
||||||
|
reset="\033[0m"
|
||||||
|
underline="\033[4;37m"
|
||||||
|
reverse=""
|
||||||
|
white="\033[0;37m"
|
||||||
|
blue="\033[0;34m"
|
||||||
|
yellow="\033[0;33m"
|
||||||
|
tan="\033[0;33m"
|
||||||
|
green="\033[1;32m"
|
||||||
|
red="\033[0;31m"
|
||||||
|
purple="\033[0;35m"
|
||||||
|
gray="\033[0;37m"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
_alert_() {
|
_alert_() {
|
||||||
# DESC: Controls all printing of messages to log files and stdout.
|
# DESC: Controls all printing of messages to log files and stdout.
|
||||||
@@ -237,28 +317,32 @@ _alert_() {
|
|||||||
local function_name color
|
local function_name color
|
||||||
local alertType="${1}"
|
local alertType="${1}"
|
||||||
local message="${2}"
|
local message="${2}"
|
||||||
local line="${3:-}" # Optional line number
|
local line="${3:-}" # Optional line number
|
||||||
|
|
||||||
if [[ -n "${line}" && "${alertType}" =~ ^(fatal|error) && "${FUNCNAME[2]}" != "_trapCleanup_" ]]; then
|
if [[ -n ${line} && ${alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
message="${message} (line: ${line}) $(_functionStack_)"
|
message="${message} (line: ${line}) $(_functionStack_)"
|
||||||
elif [[ -n "${line}" && "${FUNCNAME[2]}" != "_trapCleanup_" ]]; then
|
elif [[ -n ${line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
message="${message} (line: ${line})"
|
message="${message} (line: ${line})"
|
||||||
elif [[ -z "${line}" && "${alertType}" =~ ^(fatal|error) && "${FUNCNAME[2]}" != "_trapCleanup_" ]]; then
|
elif [[ -z ${line} && ${alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
message="${message} $(_functionStack_)"
|
message="${message} $(_functionStack_)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${alertType}" =~ ^(error|fatal) ]]; then
|
if [[ ${alertType} =~ ^(error|fatal) ]]; then
|
||||||
color="${bold}${red}"
|
color="${bold}${red}"
|
||||||
elif [ "${alertType}" = "warning" ]; then
|
elif [ "${alertType}" == "info" ]; then
|
||||||
|
color="${gray}"
|
||||||
|
elif [ "${alertType}" == "warning" ]; then
|
||||||
color="${red}"
|
color="${red}"
|
||||||
elif [ "${alertType}" = "success" ]; then
|
elif [ "${alertType}" == "success" ]; then
|
||||||
color="${green}"
|
color="${green}"
|
||||||
elif [ "${alertType}" = "debug" ]; then
|
elif [ "${alertType}" == "debug" ]; then
|
||||||
color="${purple}"
|
color="${purple}"
|
||||||
elif [ "${alertType}" = "header" ]; then
|
elif [ "${alertType}" == "header" ]; then
|
||||||
color="${bold}${tan}"
|
color="${bold}${tan}"
|
||||||
elif [[ "${alertType}" =~ ^(input|notice) ]]; then
|
elif [ ${alertType} == "notice" ]; then
|
||||||
color="${bold}"
|
color="${bold}"
|
||||||
|
elif [ ${alertType} == "input" ]; then
|
||||||
|
color="${bold}${underline}"
|
||||||
elif [ "${alertType}" = "dryrun" ]; then
|
elif [ "${alertType}" = "dryrun" ]; then
|
||||||
color="${blue}"
|
color="${blue}"
|
||||||
else
|
else
|
||||||
@@ -268,7 +352,7 @@ _alert_() {
|
|||||||
_writeToScreen_() {
|
_writeToScreen_() {
|
||||||
|
|
||||||
("${QUIET}") && return 0 # Print to console when script is not 'quiet'
|
("${QUIET}") && return 0 # Print to console when script is not 'quiet'
|
||||||
[[ ${VERBOSE} == false && "${alertType}" =~ ^(debug|verbose) ]] && return 0
|
[[ ${VERBOSE} == false && ${alertType} =~ ^(debug|verbose) ]] && return 0
|
||||||
|
|
||||||
if ! [[ -t 1 ]]; then # Don't use colors on non-recognized terminals
|
if ! [[ -t 1 ]]; then # Don't use colors on non-recognized terminals
|
||||||
color=""
|
color=""
|
||||||
@@ -280,11 +364,13 @@ _alert_() {
|
|||||||
_writeToScreen_
|
_writeToScreen_
|
||||||
|
|
||||||
_writeToLog_() {
|
_writeToLog_() {
|
||||||
[[ "${alertType}" == "input" ]] && return 0
|
[[ ${alertType} == "input" ]] && return 0
|
||||||
[[ "${LOGLEVEL}" =~ (off|OFF|Off) ]] && return 0
|
[[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0
|
||||||
[ -z "${LOGFILE:-}" ] && LOGFILE="$(pwd)/$(basename "$0").log"
|
if [ -z "${LOGFILE:-}" ]; then
|
||||||
[ ! -d "$(dirname "${LOGFILE}")" ] && command mkdir -p "$(dirname "${LOGFILE}")"
|
LOGFILE="$(pwd)/$(basename "$0").log"
|
||||||
[[ ! -f "${LOGFILE}" ]] && touch "${LOGFILE}"
|
fi
|
||||||
|
[ ! -d "$(dirname "${LOGFILE}")" ] && mkdir -p "$(dirname "${LOGFILE}")"
|
||||||
|
[[ ! -f ${LOGFILE} ]] && touch "${LOGFILE}"
|
||||||
|
|
||||||
# Don't use colors in logs
|
# Don't use colors in logs
|
||||||
if command -v gsed &>/dev/null; then
|
if command -v gsed &>/dev/null; then
|
||||||
@@ -304,22 +390,27 @@ _alert_() {
|
|||||||
_writeToLog_
|
_writeToLog_
|
||||||
;;
|
;;
|
||||||
INFO | info | Info)
|
INFO | info | Info)
|
||||||
if [[ "${alertType}" =~ ^(die|error|fatal|warning|info|notice|success) ]]; then
|
if [[ ${alertType} =~ ^(error|fatal|warning|info|notice|success) ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
NOTICE | notice | Notice)
|
||||||
|
if [[ ${alertType} =~ ^(error|fatal|warning|notice|success) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
WARN | warn | Warn)
|
WARN | warn | Warn)
|
||||||
if [[ "${alertType}" =~ ^(die|error|fatal|warning) ]]; then
|
if [[ ${alertType} =~ ^(error|fatal|warning) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
ERROR | error | Error)
|
ERROR | error | Error)
|
||||||
if [[ "${alertType}" =~ ^(die|error|fatal) ]]; then
|
if [[ ${alertType} =~ ^(error|fatal) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
FATAL | fatal | Fatal)
|
FATAL | fatal | Fatal)
|
||||||
if [[ "${alertType}" =~ ^(die|fatal) ]]; then
|
if [[ ${alertType} =~ ^fatal ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -327,7 +418,7 @@ _alert_() {
|
|||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [[ "${alertType}" =~ ^(die|error|fatal) ]]; then
|
if [[ ${alertType} =~ ^(error|fatal) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -343,23 +434,35 @@ success() { _alert_ success "${1}" "${2:-}"; }
|
|||||||
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
||||||
input() { _alert_ input "${1}" "${2:-}"; }
|
input() { _alert_ input "${1}" "${2:-}"; }
|
||||||
header() { _alert_ header "== ${1} ==" "${2:-}"; }
|
header() { _alert_ header "== ${1} ==" "${2:-}"; }
|
||||||
die() {
|
debug() { _alert_ debug "${1}" "${2:-}"; }
|
||||||
_alert_ fatal "${1}" "${2:-}"
|
|
||||||
_safeExit_ "1"
|
|
||||||
}
|
|
||||||
fatal() {
|
fatal() {
|
||||||
_alert_ fatal "${1}" "${2:-}"
|
_alert_ fatal "${1}" "${2:-}"
|
||||||
_safeExit_ "1"
|
_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 | notice | info | debug | dryrun | header | success) continue ;; esac
|
||||||
|
funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
|
||||||
|
done
|
||||||
|
printf "( "
|
||||||
|
printf %s "${funcStackResponse[0]}"
|
||||||
|
printf ' < %s' "${funcStackResponse[@]:1}"
|
||||||
|
printf ' )\n'
|
||||||
|
}
|
||||||
|
|
||||||
_safeExit_() {
|
_safeExit_() {
|
||||||
# DESC: Cleanup and exit from a script
|
# DESC: Cleanup and exit from a script
|
||||||
# ARGS: $1 (optional) - Exit code (defaults to 0)
|
# ARGS: $1 (optional) - Exit code (defaults to 0)
|
||||||
# OUTS: None
|
# OUTS: None
|
||||||
|
|
||||||
if [[ -d "${SCRIPT_LOCK:-}" ]]; then
|
if [[ -d ${SCRIPT_LOCK:-} ]]; then
|
||||||
if command rm -rf "${SCRIPT_LOCK}"; then
|
if command rm -rf "${SCRIPT_LOCK}"; then
|
||||||
debug "Removing script lock"
|
debug "Removing script lock"
|
||||||
else
|
else
|
||||||
@@ -367,7 +470,7 @@ _safeExit_() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -n "${TMP_DIR:-}" && -d "${TMP_DIR:-}" ]]; then
|
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
|
||||||
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
||||||
# Do something here to save TMP_DIR on a non-zero script exit for debugging
|
# Do something here to save TMP_DIR on a non-zero script exit for debugging
|
||||||
command rm -r "${TMP_DIR}"
|
command rm -r "${TMP_DIR}"
|
||||||
@@ -401,7 +504,7 @@ _trapCleanup_() {
|
|||||||
|
|
||||||
funcstack="'$(echo "$funcstack" | sed -E 's/ / < /g')'"
|
funcstack="'$(echo "$funcstack" | sed -E 's/ / < /g')'"
|
||||||
|
|
||||||
if [[ "${script##*/}" == "${sourced##*/}" ]]; then
|
if [[ ${script##*/} == "${sourced##*/}" ]]; then
|
||||||
fatal "${7:-} command: '${command}' (line: ${line}) [func: $(_functionStack_)]"
|
fatal "${7:-} command: '${command}' (line: ${line}) [func: $(_functionStack_)]"
|
||||||
else
|
else
|
||||||
fatal "${7:-} command: '${command}' (func: ${funcstack} called at line ${linecallfunc} of '${script##*/}') (line: $line of '${sourced##*/}') "
|
fatal "${7:-} command: '${command}' (func: ${funcstack} called at line ${linecallfunc} of '${script##*/}') (line: $line of '${sourced##*/}') "
|
||||||
@@ -454,23 +557,6 @@ _acquireScriptLock_() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_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 | 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'
|
|
||||||
}
|
|
||||||
|
|
||||||
_parseOptions_() {
|
_parseOptions_() {
|
||||||
# Iterate over options
|
# Iterate over options
|
||||||
# breaking -ab into -a -b when needed and --foo=bar into --foo bar
|
# breaking -ab into -a -b when needed and --foo=bar into --foo bar
|
||||||
@@ -547,7 +633,8 @@ _usage_() {
|
|||||||
|
|
||||||
${bold}Options:${reset}
|
${bold}Options:${reset}
|
||||||
-h, --help Display this help and exit
|
-h, --help Display this help and exit
|
||||||
--loglevel [LEVEL] One of: FATAL, ERROR, WARN, INFO, DEBUG, ALL, OFF (Default is 'ERROR')
|
--loglevel [LEVEL] One of: FATAL, ERROR, WARN, INFO, NOTICE, DEBUG, ALL, OFF
|
||||||
|
(Default is 'ERROR')
|
||||||
--logfile [FILE] Full PATH to logfile. (Default is '${HOME}/logs/$(basename "$0").log')
|
--logfile [FILE] Full PATH to logfile. (Default is '${HOME}/logs/$(basename "$0").log')
|
||||||
-n, --dryrun Non-destructive. Makes no permanent changes.
|
-n, --dryrun Non-destructive. Makes no permanent changes.
|
||||||
-q, --quiet Quiet (no output)
|
-q, --quiet Quiet (no output)
|
||||||
@@ -563,18 +650,46 @@ EOF
|
|||||||
# ################################## INITIALIZE AND RUN THE SCRIPT
|
# ################################## INITIALIZE AND RUN THE SCRIPT
|
||||||
# (Comment or uncomment the lines below to customize script behavior)
|
# (Comment or uncomment the lines below to customize script behavior)
|
||||||
|
|
||||||
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' \
|
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT
|
||||||
EXIT INT TERM SIGINT SIGQUIT
|
|
||||||
set -o errtrace # Trap errors in subshells and functions
|
# Trap errors in subshells and functions
|
||||||
set -o errexit # Exit on error. Append '||true' if you expect an error
|
set -o errtrace
|
||||||
set -o pipefail # Use last non-zero exit code in a pipeline
|
|
||||||
# shopt -s nullglob globstar # Make `for f in *.txt` work when `*.txt` matches zero files
|
# Exit on error. Append '||true' if you expect an error
|
||||||
IFS=$' \n\t' # Set IFS to preferred implementation
|
set -o errexit
|
||||||
# set -o xtrace # Run in debug mode
|
|
||||||
set -o nounset # Disallow expansion of unset variables
|
# Use last non-zero exit code in a pipeline
|
||||||
# [[ $# -eq 0 ]] && _parseOptions_ "-h" # Force arguments when invoking the script
|
set -o pipefail
|
||||||
_parseOptions_ "$@" # Parse arguments passed to script
|
|
||||||
_makeTempDir_ "$(basename "$0")" # Create a temp directory '$TMP_DIR'
|
# Make `for f in *.txt` work when `*.txt` matches zero files
|
||||||
# _acquireScriptLock_ # Acquire script lock
|
# shopt -s nullglob globstar
|
||||||
_mainScript_ # Run the main logic script
|
|
||||||
_safeExit_ # Exit cleanly
|
# Set IFS to preferred implementation
|
||||||
|
IFS=$' \n\t'
|
||||||
|
|
||||||
|
# Run in debug mode
|
||||||
|
# set -o xtrace
|
||||||
|
|
||||||
|
# Initialize color constants
|
||||||
|
_setColors_
|
||||||
|
|
||||||
|
# Disallow expansion of unset variables
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Force arguments when invoking the script
|
||||||
|
# [[ $# -eq 0 ]] && _parseOptions_ "-h"
|
||||||
|
|
||||||
|
# Parse arguments passed to script
|
||||||
|
_parseOptions_ "$@"
|
||||||
|
|
||||||
|
# Create a temp directory '$TMP_DIR'
|
||||||
|
_makeTempDir_ "$(basename "$0")"
|
||||||
|
|
||||||
|
# Acquire script lock
|
||||||
|
# _acquireScriptLock_
|
||||||
|
|
||||||
|
# Run the main logic script
|
||||||
|
_mainScript_
|
||||||
|
|
||||||
|
# Exit cleanly
|
||||||
|
_safeExit_
|
||||||
|
|||||||
38
.vscode/shellscript.code-snippets
vendored
38
.vscode/shellscript.code-snippets
vendored
@@ -19,11 +19,18 @@
|
|||||||
"scope": "shellscript",
|
"scope": "shellscript",
|
||||||
"prefix": "_c",
|
"prefix": "_c",
|
||||||
"body": [
|
"body": [
|
||||||
"# DESC:$1",
|
"# DESC:",
|
||||||
"# ARGS:\t\t${2:None}",
|
"#\t\t\t\t\t$1",
|
||||||
"# OUTS:\t\t${3:None}",
|
"# ARGS:",
|
||||||
"# USAGE:$4",
|
"#\t\t\t\t\t$2",
|
||||||
"# NOTE:$0"
|
"# OUTS:",
|
||||||
|
"#\t\t\t\t\t0 - Success",
|
||||||
|
"#\t\t\t\t\t1 - Failure",
|
||||||
|
"#\t\t\t\t\tstdout: $4",
|
||||||
|
"# USAGE:",
|
||||||
|
"#\t\t\t\t\t$4",
|
||||||
|
"# NOTES:",
|
||||||
|
"#\t\t\t\t\t$5"
|
||||||
],
|
],
|
||||||
"description": "Comment block for a function"
|
"description": "Comment block for a function"
|
||||||
},
|
},
|
||||||
@@ -44,14 +51,21 @@
|
|||||||
"prefix": "_f",
|
"prefix": "_f",
|
||||||
"body": [
|
"body": [
|
||||||
"_${1:name}_() {",
|
"_${1:name}_() {",
|
||||||
"\t\t# DESC:$2",
|
"\t\t# DESC:",
|
||||||
"\t\t# ARGS:\t\t${3:None}",
|
"\t\t#\t\t\t\t\t$2",
|
||||||
"\t\t# OUTS:\t\t${4:None}",
|
"\t\t# ARGS:",
|
||||||
"\t\t# USAGE:$5",
|
"\t\t#\t\t\t\t\t$3",
|
||||||
"\t\t# NOTE:$6",
|
"\t\t# OUTS:",
|
||||||
|
"\t\t#\t\t\t\t\t0 - Success",
|
||||||
|
"\t\t#\t\t\t\t\t1 - Failure",
|
||||||
|
"\t\t#\t\t\t\t\tstdout: $4",
|
||||||
|
"\t\t# USAGE:",
|
||||||
|
"\t\t#\t\t\t\t\t_${1:name}_ ",
|
||||||
|
"\t\t# NOTES:",
|
||||||
|
"\t\t#\t\t\t\t\t$5",
|
||||||
"\t\t",
|
"\t\t",
|
||||||
"\t\t echo \"Hello world\"",
|
"\t\t [[ $# == 0 ]] && fatal \"Missing required argument to ${FUNCNAME[0]}\"",
|
||||||
"\t\t$0",
|
"\t\t$6",
|
||||||
"}"
|
"}"
|
||||||
],
|
],
|
||||||
"description": "Add a new function"
|
"description": "Add a new function"
|
||||||
|
|||||||
395
README.md
395
README.md
@@ -1,108 +1,135 @@
|
|||||||
# Shell Scripting Templates and Utilities
|
# Shell Scripting Templates and Utilities
|
||||||
|
|
||||||
A collection of shell scripting utilities and templates used to ease the creation of BASH scripts. [BATS](https://github.com/bats-core/bats-core) provides unit testing capabilities. All tests are in the `tests/` repo.
|
A collection of BASH utility functions and script templates used to ease the creation of portable and hardened BASH scripts with sane defaults.
|
||||||
|
|
||||||
## Bash Script Template Usage
|
## Usage
|
||||||
|
|
||||||
To create a new script, copy `scriptTemplate.sh` to a new file and make it executable `chmod 755 [newscript].sh`. Place your custom script logic within the `_mainScript_` function at the top of the script.
|
There are **two Script Templates** located in the root level of this repository. The usage of these templates is described in detail below.
|
||||||
|
|
||||||
### Script Template Usage
|
BASH **Utility functions** are located within the `utilities/` folder.
|
||||||
|
|
||||||
Default flags included in the base template are:
|
Complex `sed` find/replace operations are supported with the files located in `sedfiles/`. Read [the usage instructions](sedfiles/README.md).
|
||||||
|
|
||||||
- `-h`: Prints the contents of the `_usage_` function. Edit the text in that function to provide help
|
**Automated testing** is provided using [BATS](https://github.com/bats-core/bats-core). All tests are in the `tests/` repo. A git pre-commit hook provides automated testing is located in the `.hooks/` directory. Read about [how to install the hook](.hooks/README.md).
|
||||||
- `-l [level]`: Log level of the script. One of: `FATAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `ALL`, `OFF` (Default is '`ERROR`')
|
|
||||||
- `-n`: Dryrun, sets `$DRYRUN` to `true` allowing you to write functions that will work non-destructively using the `_execute_` function
|
## Bash Script Templates Usage
|
||||||
- `-v`: Sets `$VERBOSE` to `true` and prints all debug messages to stdout
|
|
||||||
- `-q`: Runs in quiet mode, suppressing all output to stdout. Will still write to log files
|
To create a new script, copy one of the script templates to a new file and make it executable `chmod 755 [newscript].sh`. Place your custom script logic within the `_mainScript_` function at the top of the script.
|
||||||
- `--force`: If using the `_seekConfirmation_` utility function, this skips all user interaction. Implied `Yes` to all confirmations.
|
|
||||||
|
### Script Templates
|
||||||
|
|
||||||
|
There are two templates located at the root level of this repository.
|
||||||
|
|
||||||
|
- **`template_source_utils.sh`** - A lean template which attempts to source all the utility functions from this repository. You will need to update the path to the utilities folder sent to `_sourceUtilities_` at the bottom of the script. This template will not function correctly if the utilities are not found.
|
||||||
|
- **`template_standalone.sh`** - For portability, the standalone template does not assume that this repository is available. Copy and paste the individual utility functions under the `### Custom utility functions` line.
|
||||||
|
|
||||||
|
### Code Organization
|
||||||
|
|
||||||
|
The script templates are roughly split into three sections:
|
||||||
|
|
||||||
|
- TOP: Write the main logic of your script within the `_mainScript_` function. It is placed at the top of the file for easy access and editing. However, it is invoked at the end of the script after options are parsed and functions are sourced.
|
||||||
|
- MIDDLE: Functions and default variable settings are located just below `_mainScript_`.
|
||||||
|
- BOTTOM: Script initialization (BASH options, traps, call to `_mainScript_`, etc.) is at the bottom of the template
|
||||||
|
|
||||||
|
### Default Options
|
||||||
|
|
||||||
|
These default options and global variables are included in the templates and used throughout the utility functions. CLI flags to set/unset them are:
|
||||||
|
|
||||||
|
- **`-h, --help`**: Prints the contents of the `_usage_` function. Edit the text in that function to provide help
|
||||||
|
- **`--logfile [FILE]`** Full PATH to logfile. (Default is `${HOME}/logs/$(basename "$0").log`)
|
||||||
|
- **`loglevel [LEVEL]`**: Log level of the script. One of: `FATAL`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `ALL`, `OFF` (Default is '`ERROR`')
|
||||||
|
- **`-n, --dryrun`**: Dryrun, sets `$DRYRUN` to `true` allowing you to write functions that will work non-destructively using the `_execute_` function
|
||||||
|
- **`-q, --quiet`**: Runs in quiet mode, suppressing all output to stdout. Will still write to log files
|
||||||
|
- **`-v, --verbose`**: Sets `$VERBOSE` to `true` and prints all debug messages to stdout
|
||||||
|
- **`--force`**: If using the `_seekConfirmation_` utility function, this skips all user interaction. Implied `Yes` to all confirmations.
|
||||||
|
|
||||||
You can add custom script options and flags to the `_parseOptions_` function.
|
You can add custom script options and flags to the `_parseOptions_` function.
|
||||||
|
|
||||||
### Script Template Functions
|
|
||||||
|
|
||||||
scriptTemplate.sh includes some helper functions to perform common tasks.
|
|
||||||
|
|
||||||
- `_alert_` Provides alerting and logging functionality. See notes below.
|
|
||||||
- `_trapCleanup_` Cleans up files on error
|
|
||||||
- `_makeTempDir_` Creates a temp directory to house temporary files
|
|
||||||
- `_acquireScriptLock_` Acquires script lock to avoid race conditions on files
|
|
||||||
- `_functionStack_` Prints the function stack in use to aid debugging
|
|
||||||
- `_parseOptions_` Parse options and take user input (`-a`, `--some-flag`, and `--some-file [filename]` supported)
|
|
||||||
- `_usage_` Prints help text when `-h` passed
|
|
||||||
- `_safeExit_` Used to exit gracefully, cleaning up all temporary files etc.
|
|
||||||
|
|
||||||
### Script Initialization
|
### Script Initialization
|
||||||
|
|
||||||
The bottom of the script template file contains a block which initializes the script. Comment, uncomment, or change the settings here for your needs
|
The bottom of the script template file contains a block which initializes the script. Comment, uncomment, or change the settings here for your needs
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' \
|
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM ERR
|
||||||
EXIT INT TERM SIGINT SIGQUIT
|
|
||||||
set -o errtrace # Trap errors in subshells and functions
|
# Trap errors in subshells and functions
|
||||||
set -o errexit # Exit on error. Append '||true' if you expect an error
|
set -o errtrace
|
||||||
set -o pipefail # Use last non-zero exit code in a pipeline
|
|
||||||
# shopt -s nullglob globstar # Make `for f in *.txt` work when `*.txt` matches zero files
|
# Exit on error. Append '||true' if you expect an error
|
||||||
IFS=$' \n\t' # Set IFS to preferred implementation
|
set -o errexit
|
||||||
# set -o xtrace # Run in debug mode
|
|
||||||
set -o nounset # Disallow expansion of unset variables
|
# Use last non-zero exit code in a pipeline
|
||||||
# [[ $# -eq 0 ]] && _parseOptions_ "-h" # Force arguments when invoking the script
|
set -o pipefail
|
||||||
_parseOptions_ "$@" # Parse arguments passed to script
|
|
||||||
# _makeTempDir_ "$(basename "$0")" # Create a temp directory '$tmpDir'
|
# Confirm we have BASH greater than v4
|
||||||
# _acquireScriptLock_ # Acquire script lock
|
[ "${BASH_VERSINFO:-0}" -ge 4 ] || {
|
||||||
_mainScript_ # Run the main logic script
|
printf "%s\n" "ERROR: BASH_VERSINFO is '${BASH_VERSINFO:-0}'. This script requires BASH v4 or greater."
|
||||||
_safeExit_ # Exit cleanly
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make `for f in *.txt` work when `*.txt` matches zero files
|
||||||
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
|
# Set IFS to preferred implementation
|
||||||
|
IFS=$' \n\t'
|
||||||
|
|
||||||
|
# Run in debug mode
|
||||||
|
# set -o xtrace
|
||||||
|
|
||||||
|
# Source utility functions
|
||||||
|
_sourceUtilities_ "${HOME}/repos/shell-scripting-templates/utilities"
|
||||||
|
|
||||||
|
# Initialize color constants
|
||||||
|
_setColors_
|
||||||
|
|
||||||
|
# Disallow expansion of unset variables
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Force arguments when invoking the script
|
||||||
|
# [[ $# -eq 0 ]] && _parseOptions_ "-h"
|
||||||
|
|
||||||
|
# Parse arguments passed to script
|
||||||
|
_parseOptions_ "$@"
|
||||||
|
|
||||||
|
# Create a temp directory '$TMP_DIR'
|
||||||
|
# _makeTempDir_ "$(basename "$0")"
|
||||||
|
|
||||||
|
# Acquire script lock
|
||||||
|
# _acquireScriptLock_
|
||||||
|
|
||||||
|
# Source GNU utilities for use on MacOS
|
||||||
|
# _useGNUUtils_
|
||||||
|
|
||||||
|
# Run the main logic script
|
||||||
|
_mainScript_
|
||||||
|
|
||||||
|
# Exit cleanly
|
||||||
|
_safeExit_
|
||||||
```
|
```
|
||||||
|
|
||||||
# Utility Files
|
# Utility Functions
|
||||||
|
|
||||||
The files within `utilities/` contain BASH functions which can be used in your scripts. Each included function includes detailed usage information. Read the code for instructions.
|
The files within `utilities/` contain BASH functions which can be used in your scripts. Each included function includes detailed usage information. Read the inline comments within the code for detailed usage instructions.
|
||||||
|
|
||||||
## Including Utility Functions
|
## Including Utility Functions
|
||||||
|
|
||||||
Within the `utilities` folder are many BASH functions meant to ease development of more complicated scripts. These can be included in the template in two ways.
|
Within the `utilities` folder are many BASH functions meant to ease development of more complicated scripts. These can be included in the template in two ways.
|
||||||
|
|
||||||
#### 1. Copy and Paste
|
#### 1. Copy and paste into standaloneTemplate.sh
|
||||||
|
|
||||||
You can copy any complete function from the Utilities and place it into your script. Copy it beneath the end of `_mainscript_()`
|
You can copy any complete function from the Utilities and place it into your script. Copy it beneath the `### Custom utility functions` line.
|
||||||
|
|
||||||
#### 2. Source entire utility files
|
#### 2. Source all the utility files by using scriptTemplate.sh
|
||||||
|
|
||||||
You can source entire utility files by pasting the following snippet into your script beneath `_mainScript_()`. Be sure to replace `[PATH_TO]` with the full path to this repository.
|
`scriptTemplate.sh` contains a function to source all the utility files into the script. Beware, this will require a full path to the location of this repository and will result in a script that will not be portable to other systems.
|
||||||
|
|
||||||
```bash
|
|
||||||
_sourceHelperFiles_() {
|
|
||||||
# DESC: Sources script helper files.
|
|
||||||
local filesToSource
|
|
||||||
local sourceFile
|
|
||||||
filesToSource=(
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/alerts.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/baseHelpers.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/arrays.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/files.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/macOS.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/numbers.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/services.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/textProcessing.bash"
|
|
||||||
"[PATH_TO]/shell-scripting-templates/utilities/dates.bash"
|
|
||||||
)
|
|
||||||
for sourceFile in "${filesToSource[@]}"; do
|
|
||||||
[ ! -f "${sourceFile}" ] \
|
|
||||||
&& {
|
|
||||||
echo "error: Can not find sourcefile '${sourceFile}'."
|
|
||||||
echo "exiting..."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
source "${sourceFile}"
|
|
||||||
done
|
|
||||||
}
|
|
||||||
_sourceHelperFiles_
|
|
||||||
```
|
|
||||||
|
|
||||||
## alerts.bash
|
## alerts.bash
|
||||||
|
|
||||||
- `_setColors_` Sets color constants for alerting (**Note:** Colors default to a dark theme.)
|
- - **`_columnizeOutput_`** Creates a column output for key/value pairs with line wrapping for the right column (value)
|
||||||
- `_alert_` Performs alerting functions including writing to a log file and printing to screen
|
- -**`_printFuncStack_`** Prints the function stack in use. Used for debugging, and error reporting
|
||||||
|
- **`_alert_`** Performs alerting functions including writing to a log file and printing to screen
|
||||||
|
- **`_centerOutput_`** Prints text in the center of the terminal window
|
||||||
|
- **`_setColors_`** Sets color constants for alerting (**Note:** Colors default to a dark theme.)
|
||||||
|
|
||||||
Basic alerting, logging, and setting color functions (included in `scriptTemplate.sh` by default). Print messages to stdout and to a user specified logfile using the following functions.
|
Basic alerting, logging, and setting color functions (included in `scriptTemplate.sh` by default). Print messages to stdout and to a user specified logfile using the following functions.
|
||||||
|
|
||||||
@@ -111,121 +138,183 @@ debug "some text" # Printed only when in verbose (-v) mode
|
|||||||
info "some text" # Basic informational messages
|
info "some text" # Basic informational messages
|
||||||
notice "some text" # Messages which should be read. Brighter than 'info'
|
notice "some text" # Messages which should be read. Brighter than 'info'
|
||||||
warning "some text" # Non-critical warnings
|
warning "some text" # Non-critical warnings
|
||||||
error "some text" # Error state warnings. (Does not stop the script)
|
error "some text" # Prints errors and the function stack but does not stop the script.
|
||||||
fatal "some text" # Fatal errors. Exits the script
|
fatal "some text" # Fatal errors. Exits the script
|
||||||
success "some text" # Prints a success message
|
success "some text" # Prints a success message
|
||||||
header "some text" # Prints a header element
|
header "some text" # Prints a header element
|
||||||
|
dryrun "some text" # Prints commands that would be run if not in dry run (-n) mode
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the following variables for the alert functions to work.
|
The following global variables must be set for the alert functions to work
|
||||||
|
|
||||||
- `$LOGFILE` - Location of a log file
|
- **`$DEBUG`** - If `true`, prints `debug` level alerts to stdout. (Default: `false`)
|
||||||
- `$LOGLEVEL` - One of: FATAL, ERROR, WARN, INFO, DEBUG, ALL, OFF (Default is 'ERROR')
|
- **`$DRYRUN`** - If `true` does not eval commands passed to `_execute_` function. (Default: `false`)
|
||||||
- `$QUIET` - If `true`, nothing will print to STDOUT (Logs files will still be populated)
|
- **`$LOGFILE`** - Path to a log file
|
||||||
- `$DEBUG` - If `true`, prints `debug` and `verbose` level alerts to stdout
|
- **`$LOGLEVEL`** - One of: FATAL, ERROR, WARN, INFO, DEBUG, ALL, OFF (Default: `ERROR`)
|
||||||
|
- **`$QUIET`** - If `true`, prints to log file but not stdout. (Default: `false`)
|
||||||
|
|
||||||
## arrays.bash
|
## arrays.bash
|
||||||
|
|
||||||
Common functions for working with BASH arrays.
|
Utility functions for working with arrays.
|
||||||
|
|
||||||
- `_inArray_` Determine if a value is in an array
|
- **`_dedupeArray_`** Removes duplicate array elements
|
||||||
- `_join_` Joins items together with a user specified separator
|
- **`_forEachDo_`** Iterates over elements and passes each to a function
|
||||||
- `_setdiff_` Return items that exist in ARRAY1 that are do not exist in ARRAY2
|
- **`_forEachFilter_`** Iterates over elements, returning only those that are validated by a function
|
||||||
- `_removeDupes_` Removes duplicate array elements
|
- **`_forEachFind_`** Iterates over elements, returning the first value that is validated by a function
|
||||||
- `_randomArrayElement_` Selects a random item from an array
|
- **`_forEachReject_`** Iterates over elements, returning only those that are NOT validated by a function
|
||||||
|
- **`_forEachValidate_`** Iterates over elements and passes each to a function for validation
|
||||||
|
- **`_inArray_`** Determine if a value is in an array
|
||||||
|
- **`_isEmptyArray_`** Checks if an array is empty
|
||||||
|
- **`_joinArray_`** Joins items together with a user specified separator
|
||||||
|
- **`_mergeArrays_`** Merges the values of two arrays together
|
||||||
|
- **`_randomArrayElement_`** Selects a random item from an array
|
||||||
|
- **`_reverseSortArray_`** Sorts an array from highest to lowest
|
||||||
|
- **`_setdiff_`** Return items that exist in ARRAY1 that are do not exist in ARRAY2
|
||||||
|
- **`_sortArray_`** Sorts an array from lowest to highest
|
||||||
|
|
||||||
## baseHelpers.bash
|
## checks.bash
|
||||||
|
|
||||||
Commonly used functions in many scripts
|
Functions for validating common use-cases
|
||||||
|
|
||||||
- `_execute_` Executes commands with safety and logging options. Respects `DRYRUN` and `VERBOSE` flags.
|
- **`_binaryExists_`** Check if a binary exists in the PATH
|
||||||
- `_findBaseDir_` Locates the real directory of the script being run. Similar to GNU readlink -n
|
- **`_functionExists_`** Tests if a function is available in current scope
|
||||||
- `_checkBinary_` Check if a binary exists in the search PATH
|
- **`_isInternetAvailable_`** Checks if Internet connections are possible
|
||||||
- `_haveFunction_` Tests if a function exists
|
- **`_isAlpha_`** Validate that a given variable contains only alphabetic characters
|
||||||
- `_pauseScript_` Pause a script at any point and continue after user input
|
- **`_isAlphaDash_`** Validate that a given variable contains only alpha-numeric characters, as well as dashes and underscores
|
||||||
- `_progressBar_` Prints a progress bar within a for/while loop
|
- **`_isAlphaNum_`** Validate that a given variable contains only alpha-numeric characters
|
||||||
- `_rootAvailable_` Validate we have superuser access as root (via sudo if requested)
|
- **`_isDir_`** Validate that a given input points to a valid directory
|
||||||
- `_runAsRoot_` Run the requested command as root (via sudo if requested)
|
- **`_isEmail_`** Validates that an input is a valid email address
|
||||||
- `_safeExit_` Cleans up temporary files before exiting a script
|
- **`_isFile_`** Validate that a given input points to a valid file
|
||||||
- `_seekConfirmation_` Seek user input for yes/no question
|
- **`_isIPv4_`** Validates that an input is a valid IPv4 address
|
||||||
- `_setPATH_` Add directories to $PATH so script can find executables
|
- **`_isIPv6_`** Validates that an input is a valid IPv6 address
|
||||||
|
- **`_isNum_`** Validate that a given variable contains only numeric characters
|
||||||
## csv.bash
|
- **`_isTerminal_`** Checks if script is run in an interactive terminal
|
||||||
|
- **`_rootAvailable_`** Validate we have superuser access as root (via sudo if requested)
|
||||||
Functions to write to a CSV file.
|
- **`_varIsEmpty_`** Checks if a given variable is empty or null
|
||||||
|
- **`_varIsFalse_`** Checks if a given variable is false
|
||||||
- `_makeCSV_` Creates a new CSV file if one does not already exist
|
- **`_varIsTrue_`** Checks if a given variable is true
|
||||||
- `_writeCSV_` Takes passed arguments and writes them as a comma separated line
|
|
||||||
|
|
||||||
## dates.bash
|
## dates.bash
|
||||||
|
|
||||||
Common utilities for working with dates in BASH scripts.
|
Functions for working with dates and time.
|
||||||
|
|
||||||
- `_monthToNumber_` Convert a month name to a number
|
- **`_convertToUnixTimestamp_`** Converts a date to unix timestamp
|
||||||
- `_numberToMonth_` Convert a month number to its name
|
- **`_countdown_`** Sleep for a specified amount of time
|
||||||
- `_parseDate_` Takes a string as input and attempts to find a date within it to parse into component parts (day, month, year)
|
- **`_dateUnixTimestamp_`** Current time in unix timestamp
|
||||||
- `_formatDate_` Reformats dates into user specified formats
|
- **`_formatDate_`** Reformats dates into user specified formats
|
||||||
|
- **`_fromSeconds_`** Convert seconds to HH:MM:SS
|
||||||
|
- **`_monthToNumber_`** Convert a month name to a number
|
||||||
|
- **`_numberToMonth_`** Convert a month number to its name
|
||||||
|
- **`_parseDate_`** Takes a string as input and attempts to find a date within it to parse into component parts (day, month, year)
|
||||||
|
- **`_readableUnixTimestamp_`** Format unix timestamp to human readable format
|
||||||
|
- **`_toSeconds_`** Converts HH:MM:SS to seconds
|
||||||
|
|
||||||
|
## debug.bash
|
||||||
|
|
||||||
|
Functions to aid in debugging BASH scripts
|
||||||
|
|
||||||
|
- **`_pauseScript_`** Pause a script at any point and continue after user input
|
||||||
|
- **`_printAnsi_`** Helps debug ansi escape sequence in text by displaying the escape codes
|
||||||
|
- **`_printArray_`** Prints the content of array as key value pairs for easier debugging
|
||||||
|
|
||||||
## files.bash
|
## files.bash
|
||||||
|
|
||||||
Common utilities for working with files.
|
Functions for working with files.
|
||||||
|
|
||||||
- `_listFiles_` Find files in a directory. Use either glob or regex.
|
- **`_backupFile_`** Creates a backup of a specified file with .bak extension or optionally to a specified directory.
|
||||||
- `_backupFile_` Creates a backup of a specified file with .bak extension or optionally to a specified directory.
|
- **`_decryptFile_`** Decrypts a file with `openssl`
|
||||||
- `_parseFilename_` Break a filename into its component parts which and place them into prefixed variables for use in your script (dir, basename, extension, path, etc.)
|
- **`_encryptFile_`** Encrypts a file with `openssl`
|
||||||
- `_decryptFile_` Decrypts a file with `openssl`
|
- **`_extractArchive_`** Extract a compressed file
|
||||||
- `_encryptFile_` Encrypts a file with `openssl`
|
- **`_fileAbsPath_`** Finds the absolute path to a relative file or directory
|
||||||
- `_extract_` Extract a compressed file
|
- **`_fileBasename_`** Gets the basename of a file from a file name
|
||||||
- `_json2yaml_` Convert JSON to YAML uses python
|
- **`_fileContains_`** Tests whether a file contains a given pattern
|
||||||
- `_makeSymlink_` 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.
|
- **`_fileDirectory_`** Finds the directory name from a file path
|
||||||
- `_parseYAML_` Convert a YAML file into BASH variables for use in a shell script
|
- **`_fileExtension_`** Gets the extension of a file
|
||||||
- `_readFile_` Prints each line of a file
|
- **`_fileName_`** Prints a filename from a path
|
||||||
- `_sourceFile_` Source a file into a script
|
- **`_json2yaml_`** Convert JSON to YAML uses python
|
||||||
- `_uniqueFileName_` Ensure a file to be created has a unique filename to avoid overwriting other files
|
- **`_listFiles_`** Find files in a directory. Use either glob or regex.
|
||||||
- `_yaml2json_` Convert a YAML file to JSON with python
|
- **`_makeSymlink_`** 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.
|
||||||
|
- **`_parseFilename_`** Break a filename into its component parts which and place them into global variables for use in your script (dir, basename, extension, path, etc.)
|
||||||
|
- **`_parseYAML_`** Convert a YAML file into BASH variables for use in a shell script
|
||||||
|
- **`_readFile_`** Prints each line of a file
|
||||||
|
- **`_sourceFile_`** Source a file into a script
|
||||||
|
- **`_createUniqueFilename_`** Ensure a file to be created has a unique filename to avoid overwriting other files
|
||||||
|
- **`_yaml2json_`** Convert a YAML file to JSON with python
|
||||||
|
|
||||||
## macOS.bash
|
## macOS.bash
|
||||||
|
|
||||||
Functions useful when writing scripts to be run on macOS
|
Functions useful when writing scripts to be run on macOS
|
||||||
|
|
||||||
- `_haveScriptableFinder_` Determine whether we can script the Finder or not
|
- **`_guiInput_`** Ask for user input using a Mac dialog box
|
||||||
- `_guiInput_` Ask for user input using a Mac dialog box
|
- **`_haveScriptableFinder_`** Determine whether we can script the Finder or not
|
||||||
|
- **`_useGNUUtils_`** Add GNU utilities to PATH to allow consistent use of sed/grep/tar/etc. on MacOS
|
||||||
|
|
||||||
## numbers.bash
|
## misc.bash
|
||||||
|
|
||||||
Helpers to work with numbers
|
Miscellaneous functions
|
||||||
|
|
||||||
- `_fromSeconds_` Convert seconds to HH:MM:SS
|
- **`_acquireScriptLock_`** Acquire script lock to prevent running the same script a second time before the first instance exits
|
||||||
- `_toSeconds_` Converts HH:MM:SS to seconds
|
- **`_detectLinuxDistro_`** Detects the host computer's distribution of Linux
|
||||||
- `_countdown_` Sleep for a specified amount of time
|
- **`_detectMacOSVersion_`** Detects the host computer's version of macOS
|
||||||
|
- **`_detectOS_`** Detect the the host computer's operating system
|
||||||
|
- **`_execute_`** Executes commands with safety and logging options. Respects `DRYRUN` and `VERBOSE` flags.
|
||||||
|
- **`_findBaseDir_`** Locates the real directory of the script being run. Similar to GNU readlink -n
|
||||||
|
- **`_generateUUID_`** Generates a unique UUID
|
||||||
|
- **`_makeProgressBar_`** Prints a progress bar within a for/while loop
|
||||||
|
- **`_runAsRoot_`** Run the requested command as root (via sudo if requested)
|
||||||
|
- **`_seekConfirmation_`** Seek user input for yes/no question
|
||||||
|
- **`_trapCleanup_`** Cleans up after a trapped error.
|
||||||
|
|
||||||
## services.bash
|
## services.bash
|
||||||
|
|
||||||
Functions to work with external services
|
Functions to work with external services
|
||||||
|
|
||||||
- `_haveInternet_` Tests to see if there is an active Internet connection
|
- **`_haveInternet_`** Tests to see if there is an active Internet connection
|
||||||
- `_httpStatus_` Report the HTTP status of a specified URL
|
- **`_httpStatus_`** Report the HTTP status of a specified URL
|
||||||
- `_pushover_` Sends a notification via Pushover (Requires API keys)
|
- **`_pushover_`** Sends a notification via Pushover (Requires API keys)
|
||||||
|
|
||||||
## testProcessing.bash
|
## strings.bash
|
||||||
|
|
||||||
Work with strings in your script
|
Functions for string manipulation
|
||||||
|
|
||||||
- `_cleanString_` Cleans a string of text
|
- **`_cleanString_`** Cleans a string of text
|
||||||
- `_stopWords_` Removes common stopwords from a string. Requires a sed stopwords file. Customize to your needs.
|
- **`_decodeHTML_`** Decode HTML characters with sed. (Requires sed file)
|
||||||
- `_escape_` Escapes a string by adding `\` before special chars
|
- **`_decodeURL_`** Decode a URL encoded string
|
||||||
- `_htmlDecode_` Decode HTML characters with sed. (Requires sed file)
|
- **`_encodeHTML_`** Encode HTML characters with sed (Requires sed file)
|
||||||
- `_htmlEncode_` Encode HTML characters with sed (Requires sed file)
|
- **`_encodeURL_`** URL encode a string
|
||||||
- `_lower_` Convert a string to lowercase
|
- **`_escapeString_`** Escapes a string by adding `\` before special chars
|
||||||
- `_upper_` Convert a string to uppercase
|
- **`_lower_`** Convert a string to lowercase
|
||||||
- `_ltrim_` Removes all leading whitespace (from the left)
|
- **`_ltrim_`** Removes all leading whitespace (from the left)
|
||||||
- `_regex_` Use regex to validate and parse strings
|
- **`_regexCapture_`** Use regex to validate and parse strings
|
||||||
- `_rtrim_` Removes all leading whitespace (from the right)
|
- **`_rtrim_`** Removes all leading whitespace (from the right)
|
||||||
- `_trim_` Removes all leading/trailing whitespace
|
- **`_splitString_`** Split a string based on a given delimeter
|
||||||
- `_urlEncode_` URL encode a string
|
- **`_stringContains_`** Tests whether a string matches a substring
|
||||||
- `_urlDecode_` Decode a URL encoded string
|
- **`_stringRegex_`** Tests whether a string matches a regex pattern
|
||||||
|
- **`_stripANSI_`** Strips ANSI escape sequences from text
|
||||||
|
- **`_stripStopwords_`** Removes common stopwords from a string using a list of sed replacements located in an external file.
|
||||||
|
- **`_trim_`** Removes all leading/trailing whitespace
|
||||||
|
- **`_upper_`** Convert a string to uppercase
|
||||||
|
|
||||||
## A Note on Code Reuse
|
## template_utils.bash
|
||||||
|
|
||||||
|
Functions required to allow the script template and alert functions to be used
|
||||||
|
|
||||||
|
- **`_makeTempDir_`** Creates a temp directory to house temporary files
|
||||||
|
- **`_safeExit_`** Cleans up temporary files before exiting a script
|
||||||
|
- **`_setPATH_`** Add directories to $PATH so script can find executables
|
||||||
|
|
||||||
|
# Coding conventions
|
||||||
|
|
||||||
|
Where possible, I follow [defensive BASH programming](https://kfirlavi.herokuapp.com/blog/2012/11/14/defensive-bash-programming/) principles.
|
||||||
|
|
||||||
|
- Function names use camel case surrounded by underscores: `_nameOfFunction_`
|
||||||
|
- Local variable names use camel case with a starting underscore: `_localVariable`
|
||||||
|
- Global variables are in ALL_CAPS with underscores seperating words
|
||||||
|
- Exceptions to the variable an function naming rules are made for alerting functions and colors to ease my speed of programming. (Breaking years of habits is hard...) I.e. `notice "Some log item: ${blue}blue text${reset}` Where `notice` is a function and `$blue` and `$reset` are global variables but are lowercase.
|
||||||
|
- Variables are always surrounded by quotes and brackets `"${1}"` (It's verbose, but a safe practice)
|
||||||
|
- Formatting is provided by [shfmt](https://github.com/mvdan/sh) using 4 spaces for indentation
|
||||||
|
|
||||||
|
## A Note on Code Reuse and Prior Art
|
||||||
|
|
||||||
I compiled these scripting utilities over many years without having an intention to make them public. As a novice programmer, I have Googled, GitHubbed, and StackExchanged a path to solve my own scripting needs. I often lift a function whole-cloth from a GitHub repo don't keep track of its original location. I have done my best within these files to recreate my footsteps and give credit to the original creators of the code when possible. Unfortunately, I fear that I missed as many as I found. My goal in making this repository public is not to take credit for the code written by others. If you recognize something that I didn't credit, please let me know.
|
I compiled these scripting utilities over many years without having an intention to make them public. As a novice programmer, I have Googled, GitHubbed, and StackExchanged a path to solve my own scripting needs. I often lift a function whole-cloth from a GitHub repo don't keep track of its original location. I have done my best within these files to recreate my footsteps and give credit to the original creators of the code when possible. Unfortunately, I fear that I missed as many as I found. My goal in making this repository public is not to take credit for the code written by others. If you recognize something that I didn't credit, please let me know.
|
||||||
|
|
||||||
|
|||||||
@@ -1,480 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
_mainScript_() {
|
|
||||||
|
|
||||||
# Replace everything in _mainScript_() with your script's code
|
|
||||||
header "Showing alert colors"
|
|
||||||
debug "This is debug text"
|
|
||||||
info "This is info text"
|
|
||||||
notice "This is notice text"
|
|
||||||
dryrun "This is dryrun text"
|
|
||||||
warning "This is warning text"
|
|
||||||
error "This is error text"
|
|
||||||
success "This is success text"
|
|
||||||
input "This is input text"
|
|
||||||
|
|
||||||
} # end _mainScript_
|
|
||||||
|
|
||||||
# ################################## Flags and defaults
|
|
||||||
# Script specific
|
|
||||||
|
|
||||||
# Common
|
|
||||||
LOGFILE="${HOME}/logs/$(basename "$0").log"
|
|
||||||
QUIET=false
|
|
||||||
LOGLEVEL=ERROR
|
|
||||||
VERBOSE=false
|
|
||||||
FORCE=false
|
|
||||||
DRYRUN=false
|
|
||||||
declare -a ARGS=()
|
|
||||||
NOW=$(LC_ALL=C date +"%m-%d-%Y %r") # Returns: 06-14-2015 10:34:40 PM
|
|
||||||
DATESTAMP=$(LC_ALL=C date +%Y-%m-%d) # Returns: 2015-06-14
|
|
||||||
HOURSTAMP=$(LC_ALL=C date +%r) # Returns: 10:34:40 PM
|
|
||||||
TIMESTAMP=$(LC_ALL=C date +%Y%m%d_%H%M%S) # Returns: 20150614_223440
|
|
||||||
LONGDATE=$(LC_ALL=C date +"%a, %d %b %Y %H:%M:%S %z") # Returns: Sun, 10 Jan 2016 20:47:53 -0500
|
|
||||||
GMTDATE=$(LC_ALL=C date -u -R | sed 's/\+0000/GMT/') # Returns: Wed, 13 Jan 2016 15:55:29 GMT
|
|
||||||
|
|
||||||
# ################################## Custom utility functions
|
|
||||||
|
|
||||||
# ################################## Common Functions for script template
|
|
||||||
|
|
||||||
_setColors_() {
|
|
||||||
# DESC: Sets colors use for alerts.
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: echo "${blue}Some text${reset}"
|
|
||||||
|
|
||||||
if tput setaf 1 &>/dev/null; then
|
|
||||||
bold=$(tput bold)
|
|
||||||
underline=$(tput smul)
|
|
||||||
reverse=$(tput rev)
|
|
||||||
reset=$(tput sgr0)
|
|
||||||
|
|
||||||
if [[ $(tput colors) -ge 256 ]] 2>/dev/null; then
|
|
||||||
white=$(tput setaf 231)
|
|
||||||
blue=$(tput setaf 38)
|
|
||||||
yellow=$(tput setaf 11)
|
|
||||||
tan=$(tput setaf 3)
|
|
||||||
green=$(tput setaf 82)
|
|
||||||
red=$(tput setaf 1)
|
|
||||||
purple=$(tput setaf 171)
|
|
||||||
gray=$(tput setaf 250)
|
|
||||||
else
|
|
||||||
white=$(tput setaf 7)
|
|
||||||
blue=$(tput setaf 38)
|
|
||||||
yellow=$(tput setaf 3)
|
|
||||||
tan=$(tput setaf 3)
|
|
||||||
green=$(tput setaf 2)
|
|
||||||
red=$(tput setaf 1)
|
|
||||||
purple=$(tput setaf 13)
|
|
||||||
gray=$(tput setaf 7)
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
bold="\033[4;37m"
|
|
||||||
reset="\033[0m"
|
|
||||||
underline="\033[4;37m"
|
|
||||||
reverse=""
|
|
||||||
white="\033[0;37m"
|
|
||||||
blue="\033[0;34m"
|
|
||||||
yellow="\033[0;33m"
|
|
||||||
tan="\033[0;33m"
|
|
||||||
green="\033[1;32m"
|
|
||||||
red="\033[0;31m"
|
|
||||||
purple="\033[0;35m"
|
|
||||||
gray="\033[0;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
|
|
||||||
|
|
||||||
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}" == "info" ]; then
|
|
||||||
color="${gray}"
|
|
||||||
elif [ "${alertType}" == "warning" ]; then
|
|
||||||
color="${red}"
|
|
||||||
elif [ "${alertType}" == "success" ]; then
|
|
||||||
color="${green}"
|
|
||||||
elif [ "${alertType}" == "debug" ]; then
|
|
||||||
color="${purple}"
|
|
||||||
elif [ "${alertType}" == "header" ]; then
|
|
||||||
color="${bold}${tan}"
|
|
||||||
elif [ ${alertType} == "notice" ]; then
|
|
||||||
color="${bold}"
|
|
||||||
elif [ ${alertType} == "input" ]; then
|
|
||||||
color="${bold}${underline}"
|
|
||||||
elif [ "${alertType}" = "dryrun" ]; then
|
|
||||||
color="${blue}"
|
|
||||||
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=""
|
|
||||||
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
|
|
||||||
;;
|
|
||||||
NOTICE | notice | Notice)
|
|
||||||
if [[ ${alertType} =~ ^(die|error|fatal|warning|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_
|
|
||||||
|
|
||||||
error() { _alert_ error "${1}" "${2:-}"; }
|
|
||||||
warning() { _alert_ warning "${1}" "${2:-}"; }
|
|
||||||
notice() { _alert_ notice "${1}" "${2:-}"; }
|
|
||||||
info() { _alert_ info "${1}" "${2:-}"; }
|
|
||||||
success() { _alert_ success "${1}" "${2:-}"; }
|
|
||||||
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
|
||||||
input() { _alert_ input "${1}" "${2:-}"; }
|
|
||||||
header() { _alert_ header "== ${1} ==" "${2:-}"; }
|
|
||||||
debug() { _alert_ debug "${1}" "${2:-}"; }
|
|
||||||
die() {
|
|
||||||
_alert_ fatal "${1}" "${2:-}"
|
|
||||||
_safeExit_ "1"
|
|
||||||
}
|
|
||||||
fatal() {
|
|
||||||
_alert_ fatal "${1}" "${2:-}"
|
|
||||||
_safeExit_ "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
_safeExit_() {
|
|
||||||
# DESC: Cleanup and exit from a script
|
|
||||||
# ARGS: $1 (optional) - Exit code (defaults to 0)
|
|
||||||
# OUTS: None
|
|
||||||
|
|
||||||
if [[ -d ${SCRIPT_LOCK:-} ]]; then
|
|
||||||
if command rm -rf "${SCRIPT_LOCK}"; then
|
|
||||||
debug "Removing script lock"
|
|
||||||
else
|
|
||||||
warning "Script lock could not be removed. Try manually deleting ${tan}'${LOCK_DIR}'${red}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
|
|
||||||
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
|
||||||
# Do something here to save TMP_DIR on a non-zero script exit for debugging
|
|
||||||
command rm -r "${TMP_DIR}"
|
|
||||||
debug "Removing temp directory"
|
|
||||||
else
|
|
||||||
command rm -r "${TMP_DIR}"
|
|
||||||
debug "Removing temp directory"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
trap - INT TERM EXIT
|
|
||||||
exit ${1:-0}
|
|
||||||
}
|
|
||||||
|
|
||||||
_trapCleanup_() {
|
|
||||||
# DESC: Log errors and cleanup from script when an error is trapped
|
|
||||||
# ARGS: $1 - Line number where error was trapped
|
|
||||||
# $2 - Line number in function
|
|
||||||
# $3 - Command executing at the time of the trap
|
|
||||||
# $4 - Names of all shell functions currently in the execution call stack
|
|
||||||
# $5 - Scriptname
|
|
||||||
# $6 - $BASH_SOURCE
|
|
||||||
# OUTS: None
|
|
||||||
|
|
||||||
local line=${1:-} # LINENO
|
|
||||||
local linecallfunc=${2:-}
|
|
||||||
local command="${3:-}"
|
|
||||||
local funcstack="${4:-}"
|
|
||||||
local script="${5:-}"
|
|
||||||
local sourced="${6:-}"
|
|
||||||
|
|
||||||
funcstack="'$(echo "$funcstack" | sed -E 's/ / < /g')'"
|
|
||||||
|
|
||||||
if [[ ${script##*/} == "${sourced##*/}" ]]; then
|
|
||||||
fatal "${7:-} command: '${command}' (line: ${line}) [func: $(_functionStack_)]"
|
|
||||||
else
|
|
||||||
fatal "${7:-} command: '${command}' (func: ${funcstack} called at line ${linecallfunc} of '${script##*/}') (line: $line of '${sourced##*/}') "
|
|
||||||
fi
|
|
||||||
|
|
||||||
_safeExit_ "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
_makeTempDir_() {
|
|
||||||
# DESC: Creates a temp directory to house temporary files
|
|
||||||
# ARGS: $1 (Optional) - First characters/word of directory name
|
|
||||||
# OUTS: $TMP_DIR - Temporary directory
|
|
||||||
# USAGE: _makeTempDir_ "$(basename "$0")"
|
|
||||||
|
|
||||||
[ -d "${TMP_DIR:-}" ] && return 0
|
|
||||||
|
|
||||||
if [ -n "${1:-}" ]; then
|
|
||||||
TMP_DIR="${TMPDIR:-/tmp/}${1}.$RANDOM.$RANDOM.$$"
|
|
||||||
else
|
|
||||||
TMP_DIR="${TMPDIR:-/tmp/}$(basename "$0").$RANDOM.$RANDOM.$RANDOM.$$"
|
|
||||||
fi
|
|
||||||
(umask 077 && mkdir "${TMP_DIR}") || {
|
|
||||||
fatal "Could not create temporary directory! Exiting."
|
|
||||||
}
|
|
||||||
debug "\$TMP_DIR=${TMP_DIR}"
|
|
||||||
}
|
|
||||||
|
|
||||||
_acquireScriptLock_() {
|
|
||||||
# DESC: Acquire script lock
|
|
||||||
# ARGS: $1 (optional) - Scope of script execution lock (system or user)
|
|
||||||
# OUTS: $SCRIPT_LOCK - Path to the directory indicating we have the script lock
|
|
||||||
# NOTE: This lock implementation is extremely simple but should be reliable
|
|
||||||
# across all platforms. It does *not* support locking a script with
|
|
||||||
# symlinks or multiple hardlinks as there's no portable way of doing so.
|
|
||||||
# If the lock was acquired it's automatically released in _safeExit_()
|
|
||||||
|
|
||||||
local LOCK_DIR
|
|
||||||
if [[ ${1:-} == 'system' ]]; then
|
|
||||||
LOCK_DIR="${TMPDIR:-/tmp/}$(basename "$0").lock"
|
|
||||||
else
|
|
||||||
LOCK_DIR="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
|
|
||||||
readonly SCRIPT_LOCK="${LOCK_DIR}"
|
|
||||||
debug "Acquired script lock: ${tan}${SCRIPT_LOCK}${purple}"
|
|
||||||
else
|
|
||||||
error "Unable to acquire script lock: ${tan}${LOCK_DIR}${red}"
|
|
||||||
fatal "If you trust the script isn't running, delete the lock dir"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_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 | 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'
|
|
||||||
}
|
|
||||||
|
|
||||||
_parseOptions_() {
|
|
||||||
# Iterate over options
|
|
||||||
# breaking -ab into -a -b when needed and --foo=bar into --foo bar
|
|
||||||
optstring=h
|
|
||||||
unset options
|
|
||||||
while (($#)); do
|
|
||||||
case $1 in
|
|
||||||
# If option is of type -ab
|
|
||||||
-[!-]?*)
|
|
||||||
# Loop over each character starting with the second
|
|
||||||
for ((i = 1; i < ${#1}; i++)); do
|
|
||||||
c=${1:i:1}
|
|
||||||
options+=("-$c") # Add current char to options
|
|
||||||
# If option takes a required argument, and it's not the last char make
|
|
||||||
# the rest of the string its argument
|
|
||||||
if [[ $optstring == *"$c:"* && ${1:i+1} ]]; then
|
|
||||||
options+=("${1:i+1}")
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
;;
|
|
||||||
# If option is of type --foo=bar
|
|
||||||
--?*=*) options+=("${1%%=*}" "${1#*=}") ;;
|
|
||||||
# add --endopts for --
|
|
||||||
--) options+=(--endopts) ;;
|
|
||||||
# Otherwise, nothing special
|
|
||||||
*) options+=("$1") ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
set -- "${options[@]:-}"
|
|
||||||
unset options
|
|
||||||
|
|
||||||
# Read the options and set stuff
|
|
||||||
while [[ ${1:-} == -?* ]]; do
|
|
||||||
case $1 in
|
|
||||||
# Custom options
|
|
||||||
|
|
||||||
# Common options
|
|
||||||
-h | --help)
|
|
||||||
_usage_ >&2
|
|
||||||
_safeExit_
|
|
||||||
;;
|
|
||||||
--loglevel)
|
|
||||||
shift
|
|
||||||
LOGLEVEL=${1}
|
|
||||||
;;
|
|
||||||
--logfile)
|
|
||||||
shift
|
|
||||||
LOGFILE="${1}"
|
|
||||||
;;
|
|
||||||
-n | --dryrun) DRYRUN=true ;;
|
|
||||||
-v | --verbose) VERBOSE=true ;;
|
|
||||||
-q | --quiet) QUIET=true ;;
|
|
||||||
--force) FORCE=true ;;
|
|
||||||
--endopts)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*) fatal "invalid option: '$1'." ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
ARGS+=("$@") # Store the remaining user input as arguments.
|
|
||||||
}
|
|
||||||
|
|
||||||
_usage_() {
|
|
||||||
cat <<EOF
|
|
||||||
|
|
||||||
${bold}$(basename "$0") [OPTION]... [FILE]...${reset}
|
|
||||||
|
|
||||||
This is a script template. Edit this description to print help to users.
|
|
||||||
|
|
||||||
${bold}Options:${reset}
|
|
||||||
-h, --help Display this help and exit
|
|
||||||
--loglevel [LEVEL] One of: FATAL, ERROR, WARN, INFO, NOTICE, DEBUG, ALL, OFF
|
|
||||||
(Default is 'ERROR')
|
|
||||||
--logfile [FILE] Full PATH to logfile. (Default is '${HOME}/logs/$(basename "$0").log')
|
|
||||||
-n, --dryrun Non-destructive. Makes no permanent changes.
|
|
||||||
-q, --quiet Quiet (no output)
|
|
||||||
-v, --verbose Output more information. (Items echoed to 'verbose')
|
|
||||||
--force Skip all user interaction. Implied 'Yes' to all actions.
|
|
||||||
|
|
||||||
${bold}Example Usage:${reset}
|
|
||||||
|
|
||||||
$ $(basename "$0") -vn --logfile "/path/to/file.log" --loglevel 'WARN'
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
# ################################## INITIALIZE AND RUN THE SCRIPT
|
|
||||||
# (Comment or uncomment the lines below to customize script behavior)
|
|
||||||
|
|
||||||
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT
|
|
||||||
|
|
||||||
# Trap errors in subshells and functions
|
|
||||||
set -o errtrace
|
|
||||||
|
|
||||||
# Exit on error. Append '||true' if you expect an error
|
|
||||||
set -o errexit
|
|
||||||
|
|
||||||
# Use last non-zero exit code in a pipeline
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
# Make `for f in *.txt` work when `*.txt` matches zero files
|
|
||||||
# shopt -s nullglob globstar
|
|
||||||
|
|
||||||
# Set IFS to preferred implementation
|
|
||||||
IFS=$' \n\t'
|
|
||||||
|
|
||||||
# Run in debug mode
|
|
||||||
# set -o xtrace
|
|
||||||
|
|
||||||
# Initialize color constants
|
|
||||||
_setColors_
|
|
||||||
|
|
||||||
# Disallow expansion of unset variables
|
|
||||||
set -o nounset
|
|
||||||
|
|
||||||
# Force arguments when invoking the script
|
|
||||||
# [[ $# -eq 0 ]] && _parseOptions_ "-h"
|
|
||||||
|
|
||||||
# Parse arguments passed to script
|
|
||||||
_parseOptions_ "$@"
|
|
||||||
|
|
||||||
# Create a temp directory '$TMP_DIR'
|
|
||||||
# _makeTempDir_ "$(basename "$0")"
|
|
||||||
|
|
||||||
# Acquire script lock
|
|
||||||
# _acquireScriptLock_
|
|
||||||
|
|
||||||
# Run the main logic script
|
|
||||||
_mainScript_
|
|
||||||
|
|
||||||
# Exit cleanly
|
|
||||||
_safeExit_
|
|
||||||
@@ -1,2 +1,20 @@
|
|||||||
# Sed Files
|
# Sed Files
|
||||||
These files are used by utility functions to perform complex operations with sed. If you plan on using those functions, ensure they point to these files.
|
|
||||||
|
These files are used by utility functions to perform complex operations with `sed`. If you plan on using those functions, ensure they point to these files.
|
||||||
|
|
||||||
|
The functions which use these files are:
|
||||||
|
|
||||||
|
- `_stripStopwords_`
|
||||||
|
- `_encodeHTML_`
|
||||||
|
- `_decodeHTML_`
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To use these files without needing to edit their location within the utility functions themselves, follow these steps in your terminal at the root level of this repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir "${HOME}/.sed"
|
||||||
|
ln -s "$(git rev-parse --show-toplevel)/sedfiles/stopwords.sed" "${HOME}/.sed/stopwords.sed"
|
||||||
|
ln -s "$(git rev-parse --show-toplevel)/sedfiles/stopwords.sed" "${HOME}/.sed/htmlEncode.sed"
|
||||||
|
ln -s "$(git rev-parse --show-toplevel)/sedfiles/stopwords.sed" "${HOME}/.sed/htmlDecode.sed"
|
||||||
|
```
|
||||||
|
|||||||
294
template_source_utils.sh
Executable file
294
template_source_utils.sh
Executable file
@@ -0,0 +1,294 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
_mainScript_() {
|
||||||
|
# Replace everything in _mainScript_() with your script's code
|
||||||
|
header "Showing alert colors"
|
||||||
|
debug "This is debug text"
|
||||||
|
info "This is info text"
|
||||||
|
notice "This is notice text"
|
||||||
|
dryrun "This is dryrun text"
|
||||||
|
warning "This is warning text"
|
||||||
|
error "This is error text"
|
||||||
|
success "This is success text"
|
||||||
|
input "This is input text"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#/_mainsScript_()
|
||||||
|
|
||||||
|
# ################################## Flags and defaults
|
||||||
|
# Script specific
|
||||||
|
|
||||||
|
# # Required variables
|
||||||
|
LOGFILE="${HOME}/logs/$(basename "$0").log"
|
||||||
|
QUIET=false
|
||||||
|
LOGLEVEL=ERROR
|
||||||
|
VERBOSE=false
|
||||||
|
FORCE=false
|
||||||
|
DRYRUN=false
|
||||||
|
declare -a ARGS=()
|
||||||
|
|
||||||
|
# ################################## Functions required for this template to work
|
||||||
|
|
||||||
|
_trapCleanup_() {
|
||||||
|
# DESC:
|
||||||
|
# Log errors and cleanup from script when an error is trapped. Called by 'trap'
|
||||||
|
# ARGS:
|
||||||
|
# $1: Line number where error was trapped
|
||||||
|
# $2: Line number in function
|
||||||
|
# $3: Command executing at the time of the trap
|
||||||
|
# $4: Names of all shell functions currently in the execution call stack
|
||||||
|
# $5: Scriptname
|
||||||
|
# $6: $BASH_SOURCE
|
||||||
|
# USAGE:
|
||||||
|
# trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM ERR
|
||||||
|
# OUTS:
|
||||||
|
# Exits script with error code 1
|
||||||
|
|
||||||
|
local _line=${1:-} # LINENO
|
||||||
|
local _linecallfunc=${2:-}
|
||||||
|
local _command="${3:-}"
|
||||||
|
local _funcstack="${4:-}"
|
||||||
|
local _script="${5:-}"
|
||||||
|
local _sourced="${6:-}"
|
||||||
|
|
||||||
|
if [[ "$(declare -f "fatal")" && "$(declare -f "_printFuncStack_")" ]]; then
|
||||||
|
_funcstack="'$(echo "${_funcstack}" | sed -E 's/ / < /g')'"
|
||||||
|
if [[ ${_script##*/} == "${_sourced##*/}" ]]; then
|
||||||
|
fatal "${7:-} command: '${_command}' (line: ${_line}) [func: $(_printFuncStack_)]"
|
||||||
|
else
|
||||||
|
fatal "${7:-} command: '${_command}' (func: ${_funcstack} called at line ${_linecallfunc} of '${_script##*/}') (line: ${_line} of '${_sourced##*/}') "
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf "%s\n" "Fatal error trapped. Exiting..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
_safeExit_ 1
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_sourceUtilities_() {
|
||||||
|
# DESC:
|
||||||
|
# Sources bash utility functions
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Directories or files containing utility functions
|
||||||
|
# OUTS:
|
||||||
|
# 0 if success
|
||||||
|
# 1 if failure
|
||||||
|
# USAGE:
|
||||||
|
# _sourceHelperFiles_ "/path/to/dir" "path/to/file.sh"
|
||||||
|
|
||||||
|
local _filesSourced=true
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && _filesSourced=false
|
||||||
|
|
||||||
|
local _fileToSource
|
||||||
|
local _location
|
||||||
|
if [ ${_filesSourced} == true ]; then
|
||||||
|
for _location in "$@"; do
|
||||||
|
if [[ -d ${_location} ]]; then
|
||||||
|
for _fileToSource in "${_location}"/*.{sh,bash}; do
|
||||||
|
if [[ -f ${_fileToSource} ]]; then
|
||||||
|
if ! source "${_fileToSource}"; then
|
||||||
|
_filesSourced=false
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_filesSourced=false
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
elif [[ -f ${_location} ]] && [[ ${_location} =~ .*\.(sh|bash)$ ]]; then
|
||||||
|
if ! source "${_fileToSource}"; then
|
||||||
|
_filesSourced=false
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_filesSourced=false
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${_filesSourced} == true ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
printf "%s\n" "ERROR: Invalid argument to ${FUNCNAME[0]}: ${_location}"
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
_safeExit_ 1
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_parseOptions_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates through options passed to script and sets variables. Will break -ab into -a -b
|
||||||
|
# when needed and --foo=bar into --foo bar
|
||||||
|
# ARGS:
|
||||||
|
# $@ from command line
|
||||||
|
# OUTS:
|
||||||
|
# Sets array 'ARGS' containing all arguments passed to script that were not parsed as options
|
||||||
|
# USAGE:
|
||||||
|
# _parseOptions_ "$@"
|
||||||
|
|
||||||
|
# Iterate over options
|
||||||
|
local _optstring=h
|
||||||
|
declare -a _options
|
||||||
|
local _c
|
||||||
|
local i
|
||||||
|
while (($#)); do
|
||||||
|
case $1 in
|
||||||
|
# If option is of type -ab
|
||||||
|
-[!-]?*)
|
||||||
|
# Loop over each character starting with the second
|
||||||
|
for ((i = 1; i < ${#1}; i++)); do
|
||||||
|
_c=${1:i:1}
|
||||||
|
_options+=("-${_c}") # Add current char to options
|
||||||
|
# If option takes a required argument, and it's not the last char make
|
||||||
|
# the rest of the string its argument
|
||||||
|
if [[ ${_optstring} == *"${_c}:"* && ${1:i+1} ]]; then
|
||||||
|
_options+=("${1:i+1}")
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
# If option is of type --foo=bar
|
||||||
|
--?*=*) _options+=("${1%%=*}" "${1#*=}") ;;
|
||||||
|
# add --endopts for --
|
||||||
|
--) _options+=(--endopts) ;;
|
||||||
|
# Otherwise, nothing special
|
||||||
|
*) _options+=("$1") ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
set -- "${_options[@]:-}"
|
||||||
|
unset _options
|
||||||
|
|
||||||
|
# Read the options and set stuff
|
||||||
|
while [[ ${1:-} == -?* ]]; do
|
||||||
|
case $1 in
|
||||||
|
# Custom options
|
||||||
|
|
||||||
|
# Common options
|
||||||
|
-h | --help)
|
||||||
|
_usage_
|
||||||
|
_safeExit_
|
||||||
|
;;
|
||||||
|
--loglevel)
|
||||||
|
shift
|
||||||
|
LOGLEVEL=${1}
|
||||||
|
;;
|
||||||
|
--logfile)
|
||||||
|
shift
|
||||||
|
LOGFILE="${1}"
|
||||||
|
;;
|
||||||
|
-n | --dryrun) DRYRUN=true ;;
|
||||||
|
-v | --verbose) VERBOSE=true ;;
|
||||||
|
-q | --quiet) QUIET=true ;;
|
||||||
|
--force) FORCE=true ;;
|
||||||
|
--endopts)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
fatal "invalid option: $1"
|
||||||
|
else
|
||||||
|
printf "%s\n" "Invalid option: $1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
ARGS+=("$@") # Store the remaining user input as arguments.
|
||||||
|
}
|
||||||
|
|
||||||
|
_usage_() {
|
||||||
|
cat <<USAGE_TEXT
|
||||||
|
|
||||||
|
${bold}$(basename "$0") [OPTION]... [FILE]...${reset}
|
||||||
|
|
||||||
|
This is a script template. Edit this description to print help to users.
|
||||||
|
|
||||||
|
${bold}Options:${reset}
|
||||||
|
-h, --help Display this help and exit
|
||||||
|
--loglevel [LEVEL] One of: FATAL, ERROR, WARN, INFO, NOTICE, DEBUG, ALL, OFF
|
||||||
|
(Default is 'ERROR')
|
||||||
|
--logfile [FILE] Full PATH to logfile. (Default is '${HOME}/logs/$(basename "$0").log')
|
||||||
|
-n, --dryrun Non-destructive. Makes no permanent changes.
|
||||||
|
-q, --quiet Quiet (no output)
|
||||||
|
-v, --verbose Output more information. (Items echoed to 'verbose')
|
||||||
|
--force Skip all user interaction. Implied 'Yes' to all actions.
|
||||||
|
|
||||||
|
${bold}Example Usage:${reset}
|
||||||
|
|
||||||
|
${gray}# Run the script and specify log level and log file.${reset}
|
||||||
|
$(basename "$0") -vn --logfile "/path/to/file.log" --loglevel 'WARN'
|
||||||
|
USAGE_TEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
# ################################## INITIALIZE AND RUN THE SCRIPT
|
||||||
|
# (Comment or uncomment the lines below to customize script behavior)
|
||||||
|
|
||||||
|
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM
|
||||||
|
|
||||||
|
# Trap errors in subshells and functions
|
||||||
|
set -o errtrace
|
||||||
|
|
||||||
|
# Exit on error. Append '||true' if you expect an error
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
# Use last non-zero exit code in a pipeline
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# Confirm we have BASH greater than v4
|
||||||
|
[ "${BASH_VERSINFO:-0}" -ge 4 ] || {
|
||||||
|
printf "%s\n" "ERROR: BASH_VERSINFO is '${BASH_VERSINFO:-0}'. This script requires BASH v4 or greater."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make `for f in *.txt` work when `*.txt` matches zero files
|
||||||
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
|
# Set IFS to preferred implementation
|
||||||
|
IFS=$' \n\t'
|
||||||
|
|
||||||
|
# Run in debug mode
|
||||||
|
# set -o xtrace
|
||||||
|
|
||||||
|
# Source utility functions
|
||||||
|
_sourceUtilities_ "${HOME}/repos/shell-scripting-templates/utilities"
|
||||||
|
|
||||||
|
# Initialize color constants
|
||||||
|
_setColors_
|
||||||
|
|
||||||
|
# Disallow expansion of unset variables
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Force arguments when invoking the script
|
||||||
|
# [[ $# -eq 0 ]] && _parseOptions_ "-h"
|
||||||
|
|
||||||
|
# Parse arguments passed to script
|
||||||
|
_parseOptions_ "$@"
|
||||||
|
|
||||||
|
# Create a temp directory '$TMP_DIR'
|
||||||
|
# _makeTempDir_ "$(basename "$0")"
|
||||||
|
|
||||||
|
# Acquire script lock
|
||||||
|
# _acquireScriptLock_
|
||||||
|
|
||||||
|
# Source GNU utilities for use on MacOS
|
||||||
|
# _useGNUutils_
|
||||||
|
|
||||||
|
# Run the main logic script
|
||||||
|
_mainScript_
|
||||||
|
|
||||||
|
# Exit cleanly
|
||||||
|
_safeExit_
|
||||||
600
template_standalone.sh
Executable file
600
template_standalone.sh
Executable file
@@ -0,0 +1,600 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
_mainScript_() {
|
||||||
|
|
||||||
|
# Replace everything in _mainScript_() with your script's code
|
||||||
|
header "Showing alert colors"
|
||||||
|
debug "This is debug text"
|
||||||
|
info "This is info text"
|
||||||
|
notice "This is notice text"
|
||||||
|
dryrun "This is dryrun text"
|
||||||
|
warning "This is warning text"
|
||||||
|
error "This is error text"
|
||||||
|
success "This is success text"
|
||||||
|
input "This is input text"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# end _mainScript_
|
||||||
|
|
||||||
|
# ################################## Flags and defaults
|
||||||
|
# Script specific
|
||||||
|
|
||||||
|
# Required variables
|
||||||
|
LOGFILE="${HOME}/logs/$(basename "$0").log"
|
||||||
|
QUIET=false
|
||||||
|
LOGLEVEL=ERROR
|
||||||
|
VERBOSE=false
|
||||||
|
FORCE=false
|
||||||
|
DRYRUN=false
|
||||||
|
declare -a ARGS=()
|
||||||
|
|
||||||
|
# ################################## Custom utility functions (Pasted from repository)
|
||||||
|
|
||||||
|
# ################################## Functions required for this template to work
|
||||||
|
|
||||||
|
# Functions for providing alerts to the user and printing them to the log
|
||||||
|
|
||||||
|
_setColors_() {
|
||||||
|
# DESC:
|
||||||
|
# Sets colors use for alerts.
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# echo "${blue}Some text${reset}"
|
||||||
|
|
||||||
|
if tput setaf 1 >/dev/null 2>&1; then
|
||||||
|
bold=$(tput bold)
|
||||||
|
underline=$(tput smul)
|
||||||
|
reverse=$(tput rev)
|
||||||
|
reset=$(tput sgr0)
|
||||||
|
|
||||||
|
if [[ $(tput colors) -ge 256 ]] >/dev/null 2>&1; then
|
||||||
|
white=$(tput setaf 231)
|
||||||
|
blue=$(tput setaf 38)
|
||||||
|
yellow=$(tput setaf 11)
|
||||||
|
tan=$(tput setaf 3)
|
||||||
|
green=$(tput setaf 82)
|
||||||
|
red=$(tput setaf 1)
|
||||||
|
purple=$(tput setaf 171)
|
||||||
|
gray=$(tput setaf 250)
|
||||||
|
else
|
||||||
|
white=$(tput setaf 7)
|
||||||
|
blue=$(tput setaf 38)
|
||||||
|
yellow=$(tput setaf 3)
|
||||||
|
tan=$(tput setaf 3)
|
||||||
|
green=$(tput setaf 2)
|
||||||
|
red=$(tput setaf 1)
|
||||||
|
purple=$(tput setaf 13)
|
||||||
|
gray=$(tput setaf 7)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bold="\033[4;37m"
|
||||||
|
reset="\033[0m"
|
||||||
|
underline="\033[4;37m"
|
||||||
|
reverse=""
|
||||||
|
white="\033[0;37m"
|
||||||
|
blue="\033[0;34m"
|
||||||
|
yellow="\033[0;33m"
|
||||||
|
tan="\033[0;33m"
|
||||||
|
green="\033[1;32m"
|
||||||
|
red="\033[0;31m"
|
||||||
|
purple="\033[0;35m"
|
||||||
|
gray="\033[0;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:
|
||||||
|
# stdout: The message is printed to stdout
|
||||||
|
# log file: The message is printed to a log file
|
||||||
|
# USAGE:
|
||||||
|
# [_alertType] "[MESSAGE]" "${LINENO}"
|
||||||
|
# NOTES:
|
||||||
|
# - The colors of each alert type are set in this function
|
||||||
|
# - For specified alert types, the funcstac will be printed
|
||||||
|
|
||||||
|
local _color
|
||||||
|
local _alertType="${1}"
|
||||||
|
local _message="${2}"
|
||||||
|
local _line="${3:-}" # Optional line number
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal 'Missing required argument to _alert_'
|
||||||
|
|
||||||
|
if [[ -n ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
|
_message="${_message} ${gray}(line: ${_line}) $(_printFuncStack_)"
|
||||||
|
elif [[ -n ${_line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
|
_message="${_message} ${gray}(line: ${_line})"
|
||||||
|
elif [[ -z ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
|
_message="${_message} ${gray}$(_printFuncStack_)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||||
|
_color="${bold}${red}"
|
||||||
|
elif [ "${_alertType}" == "info" ]; then
|
||||||
|
_color="${gray}"
|
||||||
|
elif [ "${_alertType}" == "warning" ]; then
|
||||||
|
_color="${red}"
|
||||||
|
elif [ "${_alertType}" == "success" ]; then
|
||||||
|
_color="${green}"
|
||||||
|
elif [ "${_alertType}" == "debug" ]; then
|
||||||
|
_color="${purple}"
|
||||||
|
elif [ "${_alertType}" == "header" ]; then
|
||||||
|
_color="${bold}${white}${underline}"
|
||||||
|
elif [ ${_alertType} == "notice" ]; then
|
||||||
|
_color="${bold}"
|
||||||
|
elif [ ${_alertType} == "input" ]; then
|
||||||
|
_color="${bold}${underline}"
|
||||||
|
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 || -z ${TERM:-} ]]; then # Don't use colors on non-recognized terminals
|
||||||
|
_color=""
|
||||||
|
reset=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s ${_color}[%7s] %s${reset}\n" "$(date +"%r")" "${_alertType}" "${_message}"
|
||||||
|
}
|
||||||
|
_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
|
||||||
|
local cleanmessage="$(echo "${_message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
|
||||||
|
# Print message to log file
|
||||||
|
printf "%s [%7s] %s %s\n" "$(date +"%b %d %R:%S")" "${_alertType}" "[$(/bin/hostname)]" "${cleanmessage}" >>"${LOGFILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write specified log level data to logfile
|
||||||
|
case "${LOGLEVEL:-ERROR}" in
|
||||||
|
ALL | all | All)
|
||||||
|
_writeToLog_
|
||||||
|
;;
|
||||||
|
DEBUG | debug | Debug)
|
||||||
|
_writeToLog_
|
||||||
|
;;
|
||||||
|
INFO | info | Info)
|
||||||
|
if [[ ${_alertType} =~ ^(error|fatal|warning|info|notice|success) ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
NOTICE | notice | Notice)
|
||||||
|
if [[ ${_alertType} =~ ^(error|fatal|warning|notice|success) ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
WARN | warn | Warn)
|
||||||
|
if [[ ${_alertType} =~ ^(error|fatal|warning) ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
ERROR | error | Error)
|
||||||
|
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
FATAL | fatal | Fatal)
|
||||||
|
if [[ ${_alertType} =~ ^fatal ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
OFF | off)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||||
|
_writeToLog_
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
} # /_alert_
|
||||||
|
|
||||||
|
error() { _alert_ error "${1}" "${2:-}"; }
|
||||||
|
warning() { _alert_ warning "${1}" "${2:-}"; }
|
||||||
|
notice() { _alert_ notice "${1}" "${2:-}"; }
|
||||||
|
info() { _alert_ info "${1}" "${2:-}"; }
|
||||||
|
success() { _alert_ success "${1}" "${2:-}"; }
|
||||||
|
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
||||||
|
input() { _alert_ input "${1}" "${2:-}"; }
|
||||||
|
header() { _alert_ header "${1}" "${2:-}"; }
|
||||||
|
debug() { _alert_ debug "${1}" "${2:-}"; }
|
||||||
|
fatal() {
|
||||||
|
_alert_ fatal "${1}" "${2:-}"
|
||||||
|
_safeExit_ "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
_printFuncStack_() {
|
||||||
|
# DESC:
|
||||||
|
# Prints the function stack in use. Used for debugging, and error reporting.
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints [function]:[file]:[line]
|
||||||
|
# NOTE:
|
||||||
|
# Does not print functions from the alert class
|
||||||
|
local _i
|
||||||
|
_funcStackResponse=()
|
||||||
|
for ((_i = 1; _i < ${#BASH_SOURCE[@]}; _i++)); do
|
||||||
|
case "${FUNCNAME[$_i]}" in "_alert_" | "_trapCleanup_" | fatal | error | warning | notice | info | debug | dryrun | header | success) continue ;; esac
|
||||||
|
_funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
|
||||||
|
done
|
||||||
|
printf "( "
|
||||||
|
printf %s "${_funcStackResponse[0]}"
|
||||||
|
printf ' < %s' "${_funcStackResponse[@]:1}"
|
||||||
|
printf ' )\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
_safeExit_() {
|
||||||
|
# DESC:
|
||||||
|
# Cleanup and exit from a script
|
||||||
|
# ARGS:
|
||||||
|
# $1 (optional) - Exit code (defaults to 0)
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
|
||||||
|
if [[ -d ${SCRIPT_LOCK:-} ]]; then
|
||||||
|
if command rm -rf "${SCRIPT_LOCK}"; then
|
||||||
|
debug "Removing script lock"
|
||||||
|
else
|
||||||
|
warning "Script lock could not be removed. Try manually deleting ${tan}'${LOCK_DIR}'"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
|
||||||
|
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
||||||
|
command rm -r "${TMP_DIR}"
|
||||||
|
else
|
||||||
|
command rm -r "${TMP_DIR}"
|
||||||
|
debug "Removing temp directory"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap - INT TERM EXIT
|
||||||
|
exit ${1:-0}
|
||||||
|
}
|
||||||
|
|
||||||
|
_trapCleanup_() {
|
||||||
|
# DESC:
|
||||||
|
# Log errors and cleanup from script when an error is trapped. Called by 'trap'
|
||||||
|
# ARGS:
|
||||||
|
# $1: Line number where error was trapped
|
||||||
|
# $2: Line number in function
|
||||||
|
# $3: Command executing at the time of the trap
|
||||||
|
# $4: Names of all shell functions currently in the execution call stack
|
||||||
|
# $5: Scriptname
|
||||||
|
# $6: $BASH_SOURCE
|
||||||
|
# USAGE:
|
||||||
|
# trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM
|
||||||
|
# OUTS:
|
||||||
|
# Exits script with error code 1
|
||||||
|
|
||||||
|
local _line=${1:-} # LINENO
|
||||||
|
local _linecallfunc=${2:-}
|
||||||
|
local _command="${3:-}"
|
||||||
|
local _funcstack="${4:-}"
|
||||||
|
local _script="${5:-}"
|
||||||
|
local _sourced="${6:-}"
|
||||||
|
|
||||||
|
if [[ "$(declare -f "fatal")" && "$(declare -f "_printFuncStack_")" ]]; then
|
||||||
|
_funcstack="'$(echo "${_funcstack}" | sed -E 's/ / < /g')'"
|
||||||
|
if [[ ${_script##*/} == "${_sourced##*/}" ]]; then
|
||||||
|
fatal "${7:-} command: '${_command}' (line: ${_line}) [func: $(_printFuncStack_)]"
|
||||||
|
else
|
||||||
|
fatal "${7:-} command: '${_command}' (func: ${_funcstack} called at line ${_linecallfunc} of '${_script##*/}') (line: ${_line} of '${_sourced##*/}') "
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf "%s\n" "Fatal error trapped. Exiting..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
_safeExit_ 1
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_makeTempDir_() {
|
||||||
|
# DESC:
|
||||||
|
# Creates a temp directory to house temporary files
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Optional) - First characters/word of directory name
|
||||||
|
# OUTS:
|
||||||
|
# Sets $TMP_DIR variable to the path of the temp directory
|
||||||
|
# USAGE:
|
||||||
|
# _makeTempDir_ "$(basename "$0")"
|
||||||
|
|
||||||
|
[ -d "${TMP_DIR:-}" ] && return 0
|
||||||
|
|
||||||
|
if [ -n "${1:-}" ]; then
|
||||||
|
TMP_DIR="${TMPDIR:-/tmp/}${1}.${RANDOM}.${RANDOM}.$$"
|
||||||
|
else
|
||||||
|
TMP_DIR="${TMPDIR:-/tmp/}$(basename "$0").${RANDOM}.${RANDOM}.${RANDOM}.$$"
|
||||||
|
fi
|
||||||
|
(umask 077 && mkdir "${TMP_DIR}") || {
|
||||||
|
fatal "Could not create temporary directory! Exiting."
|
||||||
|
}
|
||||||
|
debug "\$TMP_DIR=${TMP_DIR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_acquireScriptLock_() {
|
||||||
|
# DESC:
|
||||||
|
# Acquire script lock to prevent running the same script a second time before the
|
||||||
|
# first instance exits
|
||||||
|
# ARGS:
|
||||||
|
# $1 (optional) - Scope of script execution lock (system or user)
|
||||||
|
# OUTS:
|
||||||
|
# exports $SCRIPT_LOCK - Path to the directory indicating we have the script lock
|
||||||
|
# Exits script if lock cannot be acquired
|
||||||
|
# NOTE:
|
||||||
|
# If the lock was acquired it's automatically released in _safeExit_()
|
||||||
|
|
||||||
|
local _lockDir
|
||||||
|
if [[ ${1:-} == 'system' ]]; then
|
||||||
|
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
|
||||||
|
else
|
||||||
|
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
|
||||||
|
readonly SCRIPT_LOCK="${_lockDir}"
|
||||||
|
debug "Acquired script lock: ${yellow}${SCRIPT_LOCK}${purple}"
|
||||||
|
else
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
error "Unable to acquire script lock: ${tan}${LOCK_DIR}${red}"
|
||||||
|
fatal "If you trust the script isn't running, delete the lock dir"
|
||||||
|
else
|
||||||
|
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${LOCK_DIR}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_setPATH_() {
|
||||||
|
# DESC:
|
||||||
|
# Add directories to $PATH so script can find executables
|
||||||
|
# ARGS:
|
||||||
|
# $@ - One or more paths
|
||||||
|
# OUTS: Adds items to $PATH
|
||||||
|
# USAGE:
|
||||||
|
# _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _newPath
|
||||||
|
|
||||||
|
for _newPath in "$@"; do
|
||||||
|
if [ -d "${_newPath}" ]; then
|
||||||
|
if ! echo "${PATH}" | grep -Eq "(^|:)${_newPath}($|:)"; then
|
||||||
|
if PATH="${_newPath}:${PATH}"; then
|
||||||
|
debug "Added '${_newPath}' to PATH"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
debug "_setPATH_: '${_newPath}' already exists in PATH"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
debug "_setPATH_: can not find: ${_newPath}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_useGNUutils_() {
|
||||||
|
# DESC:
|
||||||
|
# Add GNU utilities to PATH to allow consistent use of sed/grep/tar/etc. on MacOS
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 if successful
|
||||||
|
# 1 if unsuccessful
|
||||||
|
# PATH: Adds GNU utilities to the path
|
||||||
|
# USAGE:
|
||||||
|
# # if ! _useGNUUtils_; then exit 1; fi
|
||||||
|
# NOTES:
|
||||||
|
# GNU utilities can be added to MacOS using Homebrew
|
||||||
|
|
||||||
|
[ ! "$(declare -f "_setPATH_")" ] && fatal "${FUNCNAME[0]} needs function _setPATH_"
|
||||||
|
|
||||||
|
if _setPATH_ \
|
||||||
|
"/usr/local/opt/gnu-tar/libexec/gnubin" \
|
||||||
|
"/usr/local/opt/coreutils/libexec/gnubin" \
|
||||||
|
"/usr/local/opt/gnu-sed/libexec/gnubin" \
|
||||||
|
"/usr/local/opt/grep/libexec/gnubin"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_parseOptions_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates through options passed to script and sets variables. Will break -ab into -a -b
|
||||||
|
# when needed and --foo=bar into --foo bar
|
||||||
|
# ARGS:
|
||||||
|
# $@ from command line
|
||||||
|
# OUTS:
|
||||||
|
# Sets array 'ARGS' containing all arguments passed to script that were not parsed as options
|
||||||
|
# USAGE:
|
||||||
|
# _parseOptions_ "$@"
|
||||||
|
|
||||||
|
# Iterate over options
|
||||||
|
local _optstring=h
|
||||||
|
declare -a _options
|
||||||
|
local _c
|
||||||
|
local i
|
||||||
|
while (($#)); do
|
||||||
|
case $1 in
|
||||||
|
# If option is of type -ab
|
||||||
|
-[!-]?*)
|
||||||
|
# Loop over each character starting with the second
|
||||||
|
for ((i = 1; i < ${#1}; i++)); do
|
||||||
|
_c=${1:i:1}
|
||||||
|
_options+=("-${_c}") # Add current char to options
|
||||||
|
# If option takes a required argument, and it's not the last char make
|
||||||
|
# the rest of the string its argument
|
||||||
|
if [[ ${_optstring} == *"${_c}:"* && ${1:i+1} ]]; then
|
||||||
|
_options+=("${1:i+1}")
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
# If option is of type --foo=bar
|
||||||
|
--?*=*) _options+=("${1%%=*}" "${1#*=}") ;;
|
||||||
|
# add --endopts for --
|
||||||
|
--) _options+=(--endopts) ;;
|
||||||
|
# Otherwise, nothing special
|
||||||
|
*) _options+=("$1") ;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
set -- "${_options[@]:-}"
|
||||||
|
unset _options
|
||||||
|
|
||||||
|
# Read the options and set stuff
|
||||||
|
while [[ ${1:-} == -?* ]]; do
|
||||||
|
case $1 in
|
||||||
|
# Custom options
|
||||||
|
|
||||||
|
# Common options
|
||||||
|
-h | --help)
|
||||||
|
_usage_
|
||||||
|
_safeExit_
|
||||||
|
;;
|
||||||
|
--loglevel)
|
||||||
|
shift
|
||||||
|
LOGLEVEL=${1}
|
||||||
|
;;
|
||||||
|
--logfile)
|
||||||
|
shift
|
||||||
|
LOGFILE="${1}"
|
||||||
|
;;
|
||||||
|
-n | --dryrun) DRYRUN=true ;;
|
||||||
|
-v | --verbose) VERBOSE=true ;;
|
||||||
|
-q | --quiet) QUIET=true ;;
|
||||||
|
--force) FORCE=true ;;
|
||||||
|
--endopts)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
fatal "invalid option: $1"
|
||||||
|
else
|
||||||
|
printf "%s\n" "Invalid option: $1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
ARGS+=("$@") # Store the remaining user input as arguments.
|
||||||
|
}
|
||||||
|
|
||||||
|
_usage_() {
|
||||||
|
cat <<USAGE_TEXT
|
||||||
|
|
||||||
|
${bold}$(basename "$0") [OPTION]... [FILE]...${reset}
|
||||||
|
|
||||||
|
This is a script template. Edit this description to print help to users.
|
||||||
|
|
||||||
|
${bold}Options:${reset}
|
||||||
|
-h, --help Display this help and exit
|
||||||
|
--loglevel [LEVEL] One of: FATAL, ERROR, WARN, INFO, NOTICE, DEBUG, ALL, OFF
|
||||||
|
(Default is 'ERROR')
|
||||||
|
--logfile [FILE] Full PATH to logfile. (Default is '${HOME}/logs/$(basename "$0").log')
|
||||||
|
-n, --dryrun Non-destructive. Makes no permanent changes.
|
||||||
|
-q, --quiet Quiet (no output)
|
||||||
|
-v, --verbose Output more information. (Items echoed to 'verbose')
|
||||||
|
--force Skip all user interaction. Implied 'Yes' to all actions.
|
||||||
|
|
||||||
|
${bold}Example Usage:${reset}
|
||||||
|
|
||||||
|
${gray}# Run the script and specify log level and log file.${reset}
|
||||||
|
$(basename "$0") -vn --logfile "/path/to/file.log" --loglevel 'WARN'
|
||||||
|
USAGE_TEXT
|
||||||
|
}
|
||||||
|
|
||||||
|
# ################################## INITIALIZE AND RUN THE SCRIPT
|
||||||
|
# (Comment or uncomment the lines below to customize script behavior)
|
||||||
|
|
||||||
|
trap '_trapCleanup_ ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${FUNCNAME[*]}" "${0}" "${BASH_SOURCE[0]}"' EXIT INT TERM SIGINT SIGQUIT SIGTERM
|
||||||
|
|
||||||
|
# Trap errors in subshells and functions
|
||||||
|
set -o errtrace
|
||||||
|
|
||||||
|
# Exit on error. Append '||true' if you expect an error
|
||||||
|
set -o errexit
|
||||||
|
|
||||||
|
# Use last non-zero exit code in a pipeline
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# Confirm we have BASH greater than v4
|
||||||
|
[ "${BASH_VERSINFO:-0}" -ge 4 ] || {
|
||||||
|
printf "%s\n" "ERROR: BASH_VERSINFO is '${BASH_VERSINFO:-0}'. This script requires BASH v4 or greater."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Make `for f in *.txt` work when `*.txt` matches zero files
|
||||||
|
shopt -s nullglob globstar
|
||||||
|
|
||||||
|
# Set IFS to preferred implementation
|
||||||
|
IFS=$' \n\t'
|
||||||
|
|
||||||
|
# Run in debug mode
|
||||||
|
# set -o xtrace
|
||||||
|
|
||||||
|
# Initialize color constants
|
||||||
|
_setColors_
|
||||||
|
|
||||||
|
# Disallow expansion of unset variables
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
# Force arguments when invoking the script
|
||||||
|
# [[ $# -eq 0 ]] && _parseOptions_ "-h"
|
||||||
|
|
||||||
|
# Parse arguments passed to script
|
||||||
|
_parseOptions_ "$@"
|
||||||
|
|
||||||
|
# Create a temp directory '$TMP_DIR'
|
||||||
|
# _makeTempDir_ "$(basename "$0")"
|
||||||
|
|
||||||
|
# Acquire script lock
|
||||||
|
# _acquireScriptLock_
|
||||||
|
|
||||||
|
# Source GNU utilities for use on MacOS
|
||||||
|
_useGNUutils_
|
||||||
|
|
||||||
|
# Run the main logic script
|
||||||
|
_mainScript_
|
||||||
|
|
||||||
|
# Exit cleanly
|
||||||
|
_safeExit_
|
||||||
@@ -84,7 +84,7 @@ teardown() {
|
|||||||
|
|
||||||
@test "_alert_: notice: with LINE" {
|
@test "_alert_: notice: with LINE" {
|
||||||
run notice "testing" "$LINENO"
|
run notice "testing" "$LINENO"
|
||||||
assert_output --regexp ".*\[ notice\] testing \(line: [0-9]{1,3}\)"
|
assert_output --regexp ".*\[ notice\] testing .*\(line: [0-9]{1,3}\)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_alert_: refute debug" {
|
@test "_alert_: refute debug" {
|
||||||
@@ -100,7 +100,7 @@ teardown() {
|
|||||||
|
|
||||||
@test "_alert_: header" {
|
@test "_alert_: header" {
|
||||||
run header "testing"
|
run header "testing"
|
||||||
assert_output --regexp "\[ header\] == testing =="
|
assert_output --regexp "\[ header\] testing"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_alert_: info" {
|
@test "_alert_: info" {
|
||||||
@@ -110,12 +110,12 @@ teardown() {
|
|||||||
|
|
||||||
@test "_alert_: fatal: with LINE" {
|
@test "_alert_: fatal: with LINE" {
|
||||||
run fatal "testing" "$LINENO"
|
run fatal "testing" "$LINENO"
|
||||||
assert_line --index 0 --regexp ".*\[ fatal\] testing \(line: [0-9]{1,3}\) \( run:.*\)"
|
assert_line --index 0 --regexp ".*\[ fatal\] testing .*\(line: [0-9]{1,3}\) \( run:.*\)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_alert_: error" {
|
@test "_alert_: error" {
|
||||||
run error "testing"
|
run error "testing"
|
||||||
assert_output --regexp ".*\[ error\] testing \( run:.*\)"
|
assert_output --regexp ".*\[ error\] testing .*\( run:.*\)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_alert_: input" {
|
@test "_alert_: input" {
|
||||||
|
|||||||
214
test/arrays.bats
214
test/arrays.bats
@@ -8,7 +8,9 @@ load 'test_helper/bats-assert/load'
|
|||||||
######## SETUP TESTS ########
|
######## SETUP TESTS ########
|
||||||
ROOTDIR="$(git rev-parse --show-toplevel)"
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
SOURCEFILE="${ROOTDIR}/utilities/arrays.bash"
|
SOURCEFILE="${ROOTDIR}/utilities/arrays.bash"
|
||||||
|
BASEHELPERS="${ROOTDIR}/utilities/misc.bash"
|
||||||
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
CHECKS="${ROOTDIR}/utilities/checks.bash"
|
||||||
|
|
||||||
if test -f "${SOURCEFILE}" >&2; then
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
source "${SOURCEFILE}"
|
source "${SOURCEFILE}"
|
||||||
@@ -27,6 +29,22 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -f "${BASEHELPERS}" >&2; then
|
||||||
|
source "${BASEHELPERS}"
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${BASEHELPERS}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "${CHECKS}" >&2; then
|
||||||
|
source "${CHECKS}"
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${CHECKS}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
|
||||||
# Set arrays
|
# Set arrays
|
||||||
@@ -82,40 +100,196 @@ teardown() {
|
|||||||
assert_failure
|
assert_failure
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_join_: Join array comma" {
|
@test "_joinArray_: Join array comma" {
|
||||||
run _join_ , "${B[@]}"
|
run _joinArray_ , "${B[@]}"
|
||||||
|
assert_success
|
||||||
assert_output "1,2,3,4,5,6"
|
assert_output "1,2,3,4,5,6"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_join_: Join array space" {
|
@test "_joinArray_: Join array space" {
|
||||||
run _join_ " " "${B[@]}"
|
run _joinArray_ " " "${B[@]}"
|
||||||
|
assert_success
|
||||||
assert_output "1 2 3 4 5 6"
|
assert_output "1 2 3 4 5 6"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_join_: Join string complex" {
|
@test "_joinArray_: Join string complex" {
|
||||||
run _join_ , a "b c" d
|
run _joinArray_ , a "b c" d
|
||||||
|
assert_success
|
||||||
assert_output "a,b c,d"
|
assert_output "a,b c,d"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_join_: join string simple" {
|
@test "_joinArray_: join string simple" {
|
||||||
run _join_ / var usr tmp
|
run _joinArray_ / var usr tmp
|
||||||
|
assert_success
|
||||||
assert_output "var/usr/tmp"
|
assert_output "var/usr/tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_setdiff_: Print elements not common to arrays" {
|
@test "_setDiff_: Print elements not common to arrays" {
|
||||||
set +o nounset
|
run _setDiff_ "A[@]" "B[@]"
|
||||||
run _setdiff_ "${A[*]}" "${B[*]}"
|
assert_success
|
||||||
assert_output "one two three"
|
assert_line --index 0 "one"
|
||||||
|
assert_line --index 1 "two"
|
||||||
|
assert_line --index 2 "three"
|
||||||
|
|
||||||
run _setdiff_ "${B[*]}" "${A[*]}"
|
run _setDiff_ "B[@]" "A[@]"
|
||||||
assert_output "4 5 6"
|
assert_success
|
||||||
|
assert_line --index 0 "4"
|
||||||
|
assert_line --index 1 "5"
|
||||||
|
assert_line --index 2 "6"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_removeDupes_: remove duplicates" {
|
@test "_setDiff_: Fail when no diff" {
|
||||||
set +o nounset
|
run _setDiff_ "A[@]" "A[@]"
|
||||||
run _removeDupes_ "${DUPES[@]}"
|
assert_failure
|
||||||
assert_line --index 0 "3"
|
}
|
||||||
|
|
||||||
|
@test "_randomArrayElement_" {
|
||||||
|
run _randomArrayElement_ "${A[@]}"
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp '^one|two|three|1|2|3$'
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_dedupeArray_: remove duplicates" {
|
||||||
|
run _dedupeArray_ "${DUPES[@]}"
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "1"
|
||||||
assert_line --index 1 "2"
|
assert_line --index 1 "2"
|
||||||
assert_line --index 2 "1"
|
assert_line --index 2 "3"
|
||||||
assert_line --index 3 ""
|
}
|
||||||
|
|
||||||
|
@test "_isEmptyArray_: empty" {
|
||||||
|
declare -a emptyArray=()
|
||||||
|
run _isEmptyArray_ "${emptyArray[@]}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isEmptyArray_: not empty" {
|
||||||
|
fullArray=(1 2 3)
|
||||||
|
run _isEmptyArray_ "${fullArray[@]}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_sortArray_" {
|
||||||
|
unsorted_array=("c" "b" "c" "4" "1" "3" "a" "2" "d")
|
||||||
|
run _sortArray_ "${unsorted_array[@]}"
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "1"
|
||||||
|
assert_line --index 1 "2"
|
||||||
|
assert_line --index 2 "3"
|
||||||
|
assert_line --index 3 "4"
|
||||||
|
assert_line --index 4 "a"
|
||||||
|
assert_line --index 5 "b"
|
||||||
|
assert_line --index 6 "c"
|
||||||
|
assert_line --index 7 "c"
|
||||||
|
assert_line --index 8 "d"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_reverseSortArray_" {
|
||||||
|
unsorted_array=("c" "b" "c" "4" "1" "3" "a" "2" "d")
|
||||||
|
run _reverseSortArray_ "${unsorted_array[@]}"
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "d"
|
||||||
|
assert_line --index 1 "c"
|
||||||
|
assert_line --index 2 "c"
|
||||||
|
assert_line --index 3 "b"
|
||||||
|
assert_line --index 4 "a"
|
||||||
|
assert_line --index 5 "4"
|
||||||
|
assert_line --index 6 "3"
|
||||||
|
assert_line --index 7 "2"
|
||||||
|
assert_line --index 8 "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_mergeArrays_" {
|
||||||
|
a1=(1 2 3)
|
||||||
|
a2=(3 2 1)
|
||||||
|
run _mergeArrays_ "a1[@]" "a2[@]"
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "1"
|
||||||
|
assert_line --index 1 "2"
|
||||||
|
assert_line --index 2 "3"
|
||||||
|
assert_line --index 3 "3"
|
||||||
|
assert_line --index 4 "2"
|
||||||
|
assert_line --index 5 "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@test "_forEachDo_" {
|
||||||
|
test_func() {
|
||||||
|
printf "print value: %s\n" "$1"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
array=(1 2 3 4 5)
|
||||||
|
|
||||||
|
run _forEachDo_ "test_func" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "print value: 1"
|
||||||
|
assert_line --index 1 "print value: 2"
|
||||||
|
assert_line --index 2 "print value: 3"
|
||||||
|
assert_line --index 3 "print value: 4"
|
||||||
|
assert_line --index 4 "print value: 5"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachValidate_: success" {
|
||||||
|
array=("a" "abcdef" "ppll" "xyz")
|
||||||
|
|
||||||
|
run _forEachValidate_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachValidate_: failure" {
|
||||||
|
array=("a" "abcdef" "ppll99" "xyz")
|
||||||
|
|
||||||
|
run _forEachValidate_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachFind_: success" {
|
||||||
|
array=("1" "234" "success" "45p9")
|
||||||
|
|
||||||
|
run _forEachFind_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_success
|
||||||
|
assert_output "success"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachFind_: failure" {
|
||||||
|
array=("1" "2" "3" "4")
|
||||||
|
|
||||||
|
run _forEachFind_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachFilter_" {
|
||||||
|
array=(1 2 3 a ab 5 cde 6)
|
||||||
|
|
||||||
|
run _forEachFilter_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "a"
|
||||||
|
assert_line --index 1 "ab"
|
||||||
|
assert_line --index 2 "cde"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachReject_" {
|
||||||
|
array=(1 2 3 a ab 5 cde 6)
|
||||||
|
|
||||||
|
run _forEachReject_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "1"
|
||||||
|
assert_line --index 1 "2"
|
||||||
|
assert_line --index 2 "3"
|
||||||
|
assert_line --index 3 "5"
|
||||||
|
assert_line --index 4 "6"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachSome_: success" {
|
||||||
|
array=("1" "234" "success" "45p9")
|
||||||
|
|
||||||
|
run _forEachSome_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_forEachSome_: failure" {
|
||||||
|
array=("1" "2" "3" "4")
|
||||||
|
|
||||||
|
run _forEachSome_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
assert_failure
|
||||||
}
|
}
|
||||||
|
|||||||
256
test/checks.bats
Executable file
256
test/checks.bats
Executable file
@@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
#shellcheck disable
|
||||||
|
|
||||||
|
load 'test_helper/bats-support/load'
|
||||||
|
load 'test_helper/bats-file/load'
|
||||||
|
load 'test_helper/bats-assert/load'
|
||||||
|
|
||||||
|
######## SETUP TESTS ########
|
||||||
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
|
SOURCEFILE="${ROOTDIR}/utilities/checks.bash"
|
||||||
|
BASEHELPERS="${ROOTDIR}/utilities/misc.bash"
|
||||||
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
|
source "${SOURCEFILE}"
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${SOURCEFILE}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "${ALERTS}" >&2; then
|
||||||
|
source "${ALERTS}"
|
||||||
|
_setColors_ #Set color constants
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${ALERTS}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "${BASEHELPERS}" >&2; then
|
||||||
|
source "${BASEHELPERS}"
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${BASEHELPERS}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
TESTDIR="$(temp_make)"
|
||||||
|
curPath="${PWD}"
|
||||||
|
|
||||||
|
BATSLIB_FILE_PATH_REM="#${TEST_TEMP_DIR}"
|
||||||
|
BATSLIB_FILE_PATH_ADD='<temp>'
|
||||||
|
|
||||||
|
pushd "${TESTDIR}" &>/dev/null
|
||||||
|
|
||||||
|
######## DEFAULT FLAGS ########
|
||||||
|
LOGFILE="${TESTDIR}/logs/log.txt"
|
||||||
|
QUIET=false
|
||||||
|
LOGLEVEL=OFF
|
||||||
|
VERBOSE=false
|
||||||
|
FORCE=false
|
||||||
|
DRYRUN=false
|
||||||
|
|
||||||
|
set -o errtrace
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
set +o nounset
|
||||||
|
set +o errtrace
|
||||||
|
set +o pipefail
|
||||||
|
|
||||||
|
popd &>/dev/null
|
||||||
|
temp_del "${TESTDIR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
######## RUN TESTS ########
|
||||||
|
@test "Sanity..." {
|
||||||
|
run true
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_output ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_functionExists_: Success" {
|
||||||
|
run _functionExists_ "_varIsEmpty_"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_functionExists_: Failure" {
|
||||||
|
run _functionExists_ "_someUndefinedFunction_"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_binaryExists_: true" {
|
||||||
|
run _binaryExists_ "vi"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_binaryExists_: false" {
|
||||||
|
run _binaryExists_ "someNonexistantBinary"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isEmail_: true" {
|
||||||
|
run _isEmail_ "some.email+name@gmail.com"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isEmail_: false" {
|
||||||
|
run _isEmail_ "testemail"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isIPv4_: true" {
|
||||||
|
run _isIPv4_ "192.168.1.1"
|
||||||
|
assert_success
|
||||||
|
run _isIPv4_ "4.2.2.2"
|
||||||
|
assert_success
|
||||||
|
run _isIPv4_ "0.192.168.1"
|
||||||
|
assert_success
|
||||||
|
run _isIPv4_ "255.255.255.255"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isIPv4_: false" {
|
||||||
|
run _isIPv4_ "1.b.c.d"
|
||||||
|
assert_failure
|
||||||
|
run _isIPv4_ "1234.123.123.123"
|
||||||
|
assert_failure
|
||||||
|
run _isIPv4_ "192.168.0"
|
||||||
|
assert_failure
|
||||||
|
run _isIPv4_ "255.255.255.256"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isIPv6_: true" {
|
||||||
|
run _isIPv6_ "2001:db8:85a3:8d3:1319:8a2e:370:7348"
|
||||||
|
assert_success
|
||||||
|
run _isIPv6_ "fe80::1ff:fe23:4567:890a"
|
||||||
|
assert_success
|
||||||
|
run _isIPv6_ "fe80::1ff:fe23:4567:890a%eth2"
|
||||||
|
assert_success
|
||||||
|
run _isIPv6_ "::"
|
||||||
|
assert_success
|
||||||
|
run _isIPv6_ "2001:db8::"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isIPv6_: false" {
|
||||||
|
run _isIPv6_ "2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar"
|
||||||
|
assert_failure
|
||||||
|
run _isIPv6_ "fezy::1ff:fe23:4567:890a"
|
||||||
|
assert_failure
|
||||||
|
run _isIPv6_ "192.168.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isFile_: true" {
|
||||||
|
touch testfile.txt
|
||||||
|
run _isFile_ "testfile.txt"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isFile_: false" {
|
||||||
|
run _isFile_ "testfile.txt"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isDir_: true" {
|
||||||
|
mkdir -p "some/path"
|
||||||
|
run _isDir_ "some/path"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isDir_: false" {
|
||||||
|
run _isDir_ "some/path"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isAlpha_: true " {
|
||||||
|
testVar="abc"
|
||||||
|
run _isAlpha_ "${testVar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isAlpha_: false " {
|
||||||
|
testVar="ab c"
|
||||||
|
run _isAlpha_ "${testVar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isNum_: true " {
|
||||||
|
testVar="123"
|
||||||
|
run _isNum_ "${testVar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isNum_: false " {
|
||||||
|
testVar="12 3"
|
||||||
|
run _isNum_ "${testVar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isAlphaDash_: true " {
|
||||||
|
testVar="abc_123-xyz"
|
||||||
|
run _isAlphaDash_ "${testVar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isAlphaDash_: false " {
|
||||||
|
testVar="abc_123 xyz"
|
||||||
|
run _isAlphaDash_ "${testVar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isAlphaNum_: true " {
|
||||||
|
testVar="abc123"
|
||||||
|
run _isAlphaNum_ "${testVar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_isAlphaNum_: false " {
|
||||||
|
testVar="ab c123"
|
||||||
|
run _isAlphaNum_ "${testVar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_varIsFalse_: true" {
|
||||||
|
testvar=false
|
||||||
|
run _varIsFalse_ "${testvar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_varIsFalse_: false" {
|
||||||
|
testvar=true
|
||||||
|
run _variableIsFalse_ "${testvar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_varIsTrue_: true" {
|
||||||
|
testvar=true
|
||||||
|
run _varIsTrue_ "${testvar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_varIsTrue_: false" {
|
||||||
|
testvar=false
|
||||||
|
run _varIsTrue_ "${testvar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_varIsEmpty_: true" {
|
||||||
|
testvar=""
|
||||||
|
run _varIsEmpty_ "${testvar}"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_varIsEmpty_: false" {
|
||||||
|
testvar=test
|
||||||
|
run _varIsEmpty_ "${testvar}"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
359
test/dates.bats
359
test/dates.bats
@@ -8,6 +8,7 @@ load 'test_helper/bats-assert/load'
|
|||||||
######## SETUP TESTS ########
|
######## SETUP TESTS ########
|
||||||
ROOTDIR="$(git rev-parse --show-toplevel)"
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
SOURCEFILE="${ROOTDIR}/utilities/dates.bash"
|
SOURCEFILE="${ROOTDIR}/utilities/dates.bash"
|
||||||
|
BASEHELPERS="${ROOTDIR}/utilities/misc.bash"
|
||||||
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
if test -f "${SOURCEFILE}" >&2; then
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
@@ -27,6 +28,14 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -f "${BASEHELPERS}" >&2; then
|
||||||
|
source "${BASEHELPERS}"
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${BASEHELPERS}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
|
||||||
TESTDIR="$(temp_make)"
|
TESTDIR="$(temp_make)"
|
||||||
@@ -47,6 +56,30 @@ setup() {
|
|||||||
assert_output ""
|
assert_output ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "_dateUnixTimestamp_" {
|
||||||
|
run _dateUnixTimestamp_
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp "^[0-9]+$"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_convertToUnixTimestamp_" {
|
||||||
|
run _convertToUnixTimestamp_ "2020-07-07 18:38"
|
||||||
|
assert_success
|
||||||
|
assert_output "1594161480"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_readableUnixTimestamp_: Default Format" {
|
||||||
|
run _readableUnixTimestamp_ "1591554426"
|
||||||
|
assert_success
|
||||||
|
assert_output "2020-06-07 14:27:06"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_readableUnixTimestamp_: Custom format" {
|
||||||
|
run _readableUnixTimestamp_ "1591554426" "%Y-%m-%d"
|
||||||
|
assert_success
|
||||||
|
assert_output "2020-06-07"
|
||||||
|
}
|
||||||
|
|
||||||
@test "_monthToNumber_: 1" {
|
@test "_monthToNumber_: 1" {
|
||||||
run _monthToNumber_ "dec"
|
run _monthToNumber_ "dec"
|
||||||
@@ -85,20 +118,20 @@ setup() {
|
|||||||
@test "_parseDate_: YYYY MM DD 1" {
|
@test "_parseDate_: YYYY MM DD 1" {
|
||||||
run _parseDate_ "2019 06 01"
|
run _parseDate_ "2019 06 01"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +2019 06 01"
|
assert_output --regexp "PARSE_DATE_FOUND: +2019 06 01"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +June"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +June"
|
||||||
assert_output --regexp "_parseDate_month: +6"
|
assert_output --regexp "PARSE_DATE_MONTH: +6"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYY MM DD 2" {
|
@test "_parseDate_: YYYY MM DD 2" {
|
||||||
run _parseDate_ "this is text 2019-06-01 and more text"
|
run _parseDate_ "this is text 2019-06-01 and more text"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +2019-06-01"
|
assert_output --regexp "PARSE_DATE_FOUND: +2019-06-01"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +June"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +June"
|
||||||
assert_output --regexp "_parseDate_month: +6"
|
assert_output --regexp "PARSE_DATE_MONTH: +6"
|
||||||
assert_output --regexp "_parseDate_day: +1"
|
assert_output --regexp "PARSE_DATE_DAY: +1"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYY MM DD fail 1" {
|
@test "_parseDate_: YYYY MM DD fail 1" {
|
||||||
@@ -114,101 +147,101 @@ setup() {
|
|||||||
@test "_parseDate_: Month DD, YYYY" {
|
@test "_parseDate_: Month DD, YYYY" {
|
||||||
run _parseDate_ "this is text Oct 22, 2019 and more text"
|
run _parseDate_ "this is text Oct 22, 2019 and more text"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +Oct 22, +2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +Oct 22, +2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: Month DD YYYY" {
|
@test "_parseDate_: Month DD YYYY" {
|
||||||
run _parseDate_ "Oct 22 2019"
|
run _parseDate_ "Oct 22 2019"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +Oct 22 2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +Oct 22 2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: Month DD, YY" {
|
@test "_parseDate_: Month DD, YY" {
|
||||||
run _parseDate_ "this is text Oct 22, 19 and more text"
|
run _parseDate_ "this is text Oct 22, 19 and more text"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +Oct 22, 19"
|
assert_output --regexp "PARSE_DATE_FOUND: +Oct 22, 19"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: Month DD YY" {
|
@test "_parseDate_: Month DD YY" {
|
||||||
run _parseDate_ "Oct 22 19"
|
run _parseDate_ "Oct 22 19"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +Oct 22 19"
|
assert_output --regexp "PARSE_DATE_FOUND: +Oct 22 19"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: DD Month, YYYY" {
|
@test "_parseDate_: DD Month, YYYY" {
|
||||||
run _parseDate_ "22 June, 2019 and more text"
|
run _parseDate_ "22 June, 2019 and more text"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +22 June, 2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +22 June, 2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +June"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +June"
|
||||||
assert_output --regexp "_parseDate_month: +6"
|
assert_output --regexp "PARSE_DATE_MONTH: +6"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: DD Month YYYY" {
|
@test "_parseDate_: DD Month YYYY" {
|
||||||
run _parseDate_ "some text66-here-22 June 2019 and more text"
|
run _parseDate_ "some text66-here-22 June 2019 and more text"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +22 June 2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +22 June 2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +June"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +June"
|
||||||
assert_output --regexp "_parseDate_month: +6"
|
assert_output --regexp "PARSE_DATE_MONTH: +6"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MM DD YYYY 1" {
|
@test "_parseDate_: MM DD YYYY 1" {
|
||||||
run _parseDate_ "this is text 12 22 2019 and more text"
|
run _parseDate_ "this is text 12 22 2019 and more text"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +12 22 2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +12 22 2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +December"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +December"
|
||||||
assert_output --regexp "_parseDate_month: +12"
|
assert_output --regexp "PARSE_DATE_MONTH: +12"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MM DD YYYY 2" {
|
@test "_parseDate_: MM DD YYYY 2" {
|
||||||
run _parseDate_ "12 01 2019"
|
run _parseDate_ "12 01 2019"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +12 01 2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +12 01 2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +December"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +December"
|
||||||
assert_output --regexp "_parseDate_month: +12"
|
assert_output --regexp "PARSE_DATE_MONTH: +12"
|
||||||
assert_output --regexp "_parseDate_day: +1"
|
assert_output --regexp "PARSE_DATE_DAY: +1"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MM DD YYYY 3" {
|
@test "_parseDate_: MM DD YYYY 3" {
|
||||||
run _parseDate_ "a-test-01-12-2019-is here"
|
run _parseDate_ "a-test-01-12-2019-is here"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +01-12-2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +01-12-2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +12"
|
assert_output --regexp "PARSE_DATE_DAY: +12"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: DD MM YYYY 1 " {
|
@test "_parseDate_: DD MM YYYY 1 " {
|
||||||
run _parseDate_ "a-test-22/12/2019-is here"
|
run _parseDate_ "a-test-22/12/2019-is here"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +22/12/2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +22/12/2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +December"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +December"
|
||||||
assert_output --regexp "_parseDate_month: +12"
|
assert_output --regexp "PARSE_DATE_MONTH: +12"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: DD MM YYYY 2 " {
|
@test "_parseDate_: DD MM YYYY 2 " {
|
||||||
@@ -219,31 +252,31 @@ setup() {
|
|||||||
@test "_parseDate_: DD MM YY" {
|
@test "_parseDate_: DD MM YY" {
|
||||||
run _parseDate_ "a-test-22-12-19-is here"
|
run _parseDate_ "a-test-22-12-19-is here"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +22-12-19"
|
assert_output --regexp "PARSE_DATE_FOUND: +22-12-19"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +December"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +December"
|
||||||
assert_output --regexp "_parseDate_month: +12"
|
assert_output --regexp "PARSE_DATE_MONTH: +12"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MM DD YY 1 " {
|
@test "_parseDate_: MM DD YY 1 " {
|
||||||
run _parseDate_ "a-test-12/22/19-is here"
|
run _parseDate_ "a-test-12/22/19-is here"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +12/22/19"
|
assert_output --regexp "PARSE_DATE_FOUND: +12/22/19"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +December"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +December"
|
||||||
assert_output --regexp "_parseDate_month: +12"
|
assert_output --regexp "PARSE_DATE_MONTH: +12"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MM DD YY 2 " {
|
@test "_parseDate_: MM DD YY 2 " {
|
||||||
run _parseDate_ "6 8 19"
|
run _parseDate_ "6 8 19"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +6 8 19"
|
assert_output --regexp "PARSE_DATE_FOUND: +6 8 19"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +June"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +June"
|
||||||
assert_output --regexp "_parseDate_month: +6"
|
assert_output --regexp "PARSE_DATE_MONTH: +6"
|
||||||
assert_output --regexp "_parseDate_day: +8"
|
assert_output --regexp "PARSE_DATE_DAY: +8"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MM DD YY 3 " {
|
@test "_parseDate_: MM DD YY 3 " {
|
||||||
@@ -264,139 +297,139 @@ setup() {
|
|||||||
@test "_parseDate_: Month, YYYY 1 " {
|
@test "_parseDate_: Month, YYYY 1 " {
|
||||||
run _parseDate_ "a-test-January, 2019-is here"
|
run _parseDate_ "a-test-January, 2019-is here"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +January, 2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +January, 2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +1"
|
assert_output --regexp "PARSE_DATE_DAY: +1"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: Month, YYYY 2 " {
|
@test "_parseDate_: Month, YYYY 2 " {
|
||||||
run _parseDate_ "mar-2019"
|
run _parseDate_ "mar-2019"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +mar-2019"
|
assert_output --regexp "PARSE_DATE_FOUND: +mar-2019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +March"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +March"
|
||||||
assert_output --regexp "_parseDate_month: +3"
|
assert_output --regexp "PARSE_DATE_MONTH: +3"
|
||||||
assert_output --regexp "_parseDate_day: +1"
|
assert_output --regexp "PARSE_DATE_DAY: +1"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDDHHMM 1" {
|
@test "_parseDate_: YYYYMMDDHHMM 1" {
|
||||||
run _parseDate_ "201901220228"
|
run _parseDate_ "201901220228"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +201901220228"
|
assert_output --regexp "PARSE_DATE_FOUND: +201901220228"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
assert_output --regexp "_parseDate_hour: +2"
|
assert_output --regexp "PARSE_DATE_HOUR: +2"
|
||||||
assert_output --regexp "_parseDate_minute: +28"
|
assert_output --regexp "PARSE_DATE_MINUTE: +28"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDDHHMM 2" {
|
@test "_parseDate_: YYYYMMDDHHMM 2" {
|
||||||
run _parseDate_ "asdf 201901220228asdf "
|
run _parseDate_ "asdf 201901220228asdf "
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +201901220228"
|
assert_output --regexp "PARSE_DATE_FOUND: +201901220228"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
assert_output --regexp "_parseDate_hour: +2"
|
assert_output --regexp "PARSE_DATE_HOUR: +2"
|
||||||
assert_output --regexp "_parseDate_minute: +28"
|
assert_output --regexp "PARSE_DATE_MINUTE: +28"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDDHH 1" {
|
@test "_parseDate_: YYYYMMDDHH 1" {
|
||||||
run _parseDate_ "asdf 2019012212asdf "
|
run _parseDate_ "asdf 2019012212asdf "
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +2019012212"
|
assert_output --regexp "PARSE_DATE_FOUND: +2019012212"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
assert_output --regexp "_parseDate_hour: +12"
|
assert_output --regexp "PARSE_DATE_HOUR: +12"
|
||||||
assert_output --regexp "_parseDate_minute: +00"
|
assert_output --regexp "PARSE_DATE_MINUTE: +00"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDDHH 2" {
|
@test "_parseDate_: YYYYMMDDHH 2" {
|
||||||
run _parseDate_ "2019012212"
|
run _parseDate_ "2019012212"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +2019012212"
|
assert_output --regexp "PARSE_DATE_FOUND: +2019012212"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
assert_output --regexp "_parseDate_hour: +12"
|
assert_output --regexp "PARSE_DATE_HOUR: +12"
|
||||||
assert_output --regexp "_parseDate_minute: +00"
|
assert_output --regexp "PARSE_DATE_MINUTE: +00"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MMDDYYYY 1" {
|
@test "_parseDate_: MMDDYYYY 1" {
|
||||||
run _parseDate_ "01222019"
|
run _parseDate_ "01222019"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +01222019"
|
assert_output --regexp "PARSE_DATE_FOUND: +01222019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: MMDDYYYY 2" {
|
@test "_parseDate_: MMDDYYYY 2" {
|
||||||
run _parseDate_ "asdf 11222019 asdf"
|
run _parseDate_ "asdf 11222019 asdf"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +11222019"
|
assert_output --regexp "PARSE_DATE_FOUND: +11222019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +November"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +November"
|
||||||
assert_output --regexp "_parseDate_month: +11"
|
assert_output --regexp "PARSE_DATE_MONTH: +11"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: DDMMYYYY 1" {
|
@test "_parseDate_: DDMMYYYY 1" {
|
||||||
run _parseDate_ "16012019"
|
run _parseDate_ "16012019"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +16012019"
|
assert_output --regexp "PARSE_DATE_FOUND: +16012019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +January"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +January"
|
||||||
assert_output --regexp "_parseDate_month: +1"
|
assert_output --regexp "PARSE_DATE_MONTH: +1"
|
||||||
assert_output --regexp "_parseDate_day: +16"
|
assert_output --regexp "PARSE_DATE_DAY: +16"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: DDMMYYYY 2" {
|
@test "_parseDate_: DDMMYYYY 2" {
|
||||||
run _parseDate_ "asdf 16112019 asdf"
|
run _parseDate_ "asdf 16112019 asdf"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +16112019"
|
assert_output --regexp "PARSE_DATE_FOUND: +16112019"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +November"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +November"
|
||||||
assert_output --regexp "_parseDate_month: +11"
|
assert_output --regexp "PARSE_DATE_MONTH: +11"
|
||||||
assert_output --regexp "_parseDate_day: +16"
|
assert_output --regexp "PARSE_DATE_DAY: +16"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYDDMM " {
|
@test "_parseDate_: YYYYDDMM " {
|
||||||
run _parseDate_ "20192210"
|
run _parseDate_ "20192210"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +20192210"
|
assert_output --regexp "PARSE_DATE_FOUND: +20192210"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDD 1" {
|
@test "_parseDate_: YYYYMMDD 1" {
|
||||||
run _parseDate_ "20191022"
|
run _parseDate_ "20191022"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +20191022"
|
assert_output --regexp "PARSE_DATE_FOUND: +20191022"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +22"
|
assert_output --regexp "PARSE_DATE_DAY: +22"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDD 2" {
|
@test "_parseDate_: YYYYMMDD 2" {
|
||||||
run _parseDate_ "20191010"
|
run _parseDate_ "20191010"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output --regexp "_parseDate_found: +20191010"
|
assert_output --regexp "PARSE_DATE_FOUND: +20191010"
|
||||||
assert_output --regexp "_parseDate_year: +2019"
|
assert_output --regexp "PARSE_DATE_YEAR: +2019"
|
||||||
assert_output --regexp "_parseDate_monthName: +October"
|
assert_output --regexp "PARSE_DATE_MONTH_NAME: +October"
|
||||||
assert_output --regexp "_parseDate_month: +10"
|
assert_output --regexp "PARSE_DATE_MONTH: +10"
|
||||||
assert_output --regexp "_parseDate_day: +10"
|
assert_output --regexp "PARSE_DATE_DAY: +10"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_parseDate_: YYYYMMDD fail" {
|
@test "_parseDate_: YYYYMMDD fail" {
|
||||||
@@ -426,7 +459,33 @@ setup() {
|
|||||||
assert_output "12 27, 2019"
|
assert_output "12 27, 2019"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_formatDate_: fail - no input " {
|
@test "_convertSecs_: Seconds to human readable" {
|
||||||
run _formatDate_
|
|
||||||
assert_failure
|
run _fromSeconds_ "9255"
|
||||||
|
assert_success
|
||||||
|
assert_output "02:34:15"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_toSeconds_: HH MM SS to Seconds" {
|
||||||
|
run _toSeconds_ 12 3 33
|
||||||
|
assert_success
|
||||||
|
assert_output "43413"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_countdown_: custom message, default wait" {
|
||||||
|
run _countdown_ 10 0 "something"
|
||||||
|
assert_line --index 0 --partial "something 10"
|
||||||
|
assert_line --index 9 --partial "something 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_countdown_: default message, custom wait" {
|
||||||
|
run _countdown_ 5 0
|
||||||
|
assert_line --index 0 --partial "... 5"
|
||||||
|
assert_line --index 4 --partial "... 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_countdown_: all defaults" {
|
||||||
|
run _countdown_
|
||||||
|
assert_line --index 0 --partial "... 10"
|
||||||
|
assert_line --index 9 --partial "... 1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ load 'test_helper/bats-assert/load'
|
|||||||
|
|
||||||
######## SETUP TESTS ########
|
######## SETUP TESTS ########
|
||||||
ROOTDIR="$(git rev-parse --show-toplevel)"
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
SOURCEFILE="${ROOTDIR}/utilities/numbers.bash"
|
SOURCEFILE="${ROOTDIR}/utilities/debug.bash"
|
||||||
BASEHELPERS="${ROOTDIR}/utilities/baseHelpers.bash"
|
BASEHELPERS="${ROOTDIR}/utilities/misc.bash"
|
||||||
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
if test -f "${SOURCEFILE}" >&2; then
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
@@ -53,7 +53,7 @@ setup() {
|
|||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
FORCE=false
|
FORCE=false
|
||||||
DRYRUN=false
|
DRYRUN=false
|
||||||
|
PASS=123
|
||||||
set -o errtrace
|
set -o errtrace
|
||||||
set -o nounset
|
set -o nounset
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
@@ -63,7 +63,6 @@ teardown() {
|
|||||||
set +o nounset
|
set +o nounset
|
||||||
set +o errtrace
|
set +o errtrace
|
||||||
set +o pipefail
|
set +o pipefail
|
||||||
|
|
||||||
popd &>/dev/null
|
popd &>/dev/null
|
||||||
temp_del "${TESTDIR}"
|
temp_del "${TESTDIR}"
|
||||||
}
|
}
|
||||||
@@ -76,33 +75,28 @@ teardown() {
|
|||||||
assert_output ""
|
assert_output ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_convertSecs_: Seconds to human readable" {
|
@test "_printAnsi_" {
|
||||||
|
testString="$(tput bold)$(tput setaf 9)This is bold red text$(tput sgr0).$(tput setaf 10)This is green text$(tput sgr0)"
|
||||||
run _fromSeconds_ "9255"
|
run _printAnsi_ "${testString}"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "02:34:15"
|
assert_output "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text\e(B\e[m"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_toSeconds_: HH MM SS to Seconds" {
|
@test "_printArray_: Array" {
|
||||||
run _toSeconds_ 12 3 33
|
testArray=(1 2 3)
|
||||||
|
run _printArray_ "testArray"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "43413"
|
assert_line --index 0 "0 = 1"
|
||||||
|
assert_line --index 1 "1 = 2"
|
||||||
|
assert_line --index 2 "2 = 3"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_countdown_: custom message, default wait" {
|
@test "_printArray_: Associative array" {
|
||||||
run _countdown_ 10 0 "something"
|
declare -A assoc_array
|
||||||
assert_line --index 0 --partial "something 10"
|
assoc_array=([foo]=bar [baz]=foobar)
|
||||||
assert_line --index 9 --partial "something 1"
|
run _printArray_ "assoc_array"
|
||||||
}
|
assert_success
|
||||||
|
assert_line --index 0 "foo = bar"
|
||||||
|
assert_line --index 1 "baz = foobar"
|
||||||
|
|
||||||
@test "_countdown_: default message, custom wait" {
|
|
||||||
run _countdown_ 5 0
|
|
||||||
assert_line --index 0 --partial "... 5"
|
|
||||||
assert_line --index 4 --partial "... 1"
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_countdown_: all defaults" {
|
|
||||||
run _countdown_
|
|
||||||
assert_line --index 0 --partial "... 10"
|
|
||||||
assert_line --index 9 --partial "... 1"
|
|
||||||
}
|
}
|
||||||
116
test/files.bats
116
test/files.bats
@@ -8,7 +8,7 @@ load 'test_helper/bats-assert/load'
|
|||||||
######## SETUP TESTS ########
|
######## SETUP TESTS ########
|
||||||
ROOTDIR="$(git rev-parse --show-toplevel)"
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
SOURCEFILE="${ROOTDIR}/utilities/files.bash"
|
SOURCEFILE="${ROOTDIR}/utilities/files.bash"
|
||||||
BASEHELPERS="${ROOTDIR}/utilities/baseHelpers.bash"
|
BASEHELPERS="${ROOTDIR}/utilities/misc.bash"
|
||||||
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
if test -f "${SOURCEFILE}" >&2; then
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
@@ -260,9 +260,6 @@ _testParseFilename_() {
|
|||||||
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: tar\.gzip\.bzip$"
|
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: tar\.gzip\.bzip$"
|
||||||
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile$"
|
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile$"
|
||||||
}
|
}
|
||||||
|
|
||||||
# _parseFilename_ "test.tar.gz"
|
|
||||||
# _parseFilename_ "test.tar.gzip"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_testMakeSymlink_() {
|
_testMakeSymlink_() {
|
||||||
@@ -338,7 +335,7 @@ _testMakeSymlink_() {
|
|||||||
_testParseYAML_() {
|
_testParseYAML_() {
|
||||||
|
|
||||||
@test "_parseYAML: success" {
|
@test "_parseYAML: success" {
|
||||||
run _parseYAML_ "$YAML1"
|
run _parseYAML_ "$YAML1" ""
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "$( cat "$YAML1parse")"
|
assert_output "$( cat "$YAML1parse")"
|
||||||
}
|
}
|
||||||
@@ -383,59 +380,140 @@ _testParseYAML_() {
|
|||||||
assert_output "hello world"
|
assert_output "hello world"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: no extension" {
|
@test "_createUniqueFilename_: no extension" {
|
||||||
touch "test"
|
touch "test"
|
||||||
|
|
||||||
run _uniqueFileName_ "test"
|
run _createUniqueFilename_ "test"
|
||||||
assert_output --regexp ".*/test\.1$"
|
assert_output --regexp ".*/test\.1$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: no extension - internal integer" {
|
@test "_createUniqueFilename_: no extension - internal integer" {
|
||||||
touch "test"
|
touch "test"
|
||||||
touch "test.1"
|
touch "test.1"
|
||||||
|
|
||||||
run _uniqueFileName_ -i "test"
|
run _createUniqueFilename_ -i "test"
|
||||||
assert_output --regexp ".*/test\.2$"
|
assert_output --regexp ".*/test\.2$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: Count to 3" {
|
@test "_createUniqueFilename_: Count to 3" {
|
||||||
touch "test.txt"
|
touch "test.txt"
|
||||||
touch "test.txt.1"
|
touch "test.txt.1"
|
||||||
touch "test.txt.2"
|
touch "test.txt.2"
|
||||||
|
|
||||||
run _uniqueFileName_ "test.txt"
|
run _createUniqueFilename_ "test.txt"
|
||||||
assert_output --regexp ".*/test\.txt\.3$"
|
assert_output --regexp ".*/test\.txt\.3$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: internal integer" {
|
@test "_createUniqueFilename_: internal integer" {
|
||||||
touch "test.txt"
|
touch "test.txt"
|
||||||
touch "test.1.txt"
|
touch "test.1.txt"
|
||||||
touch "test.2.txt"
|
touch "test.2.txt"
|
||||||
|
|
||||||
run _uniqueFileName_ -i "test.txt"
|
run _createUniqueFilename_ -i "test.txt"
|
||||||
assert_output --regexp ".*/test\.3\.txt$"
|
assert_output --regexp ".*/test\.3\.txt$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: Don't confuse existing numbers" {
|
@test "_createUniqueFilename_: two extensions" {
|
||||||
|
touch "test.tar.gz"
|
||||||
|
touch "test.1.tar.gz"
|
||||||
|
touch "test.2.tar.gz"
|
||||||
|
|
||||||
|
run _createUniqueFilename_ -i "test.tar.gz"
|
||||||
|
assert_output --regexp ".*/test\.3\.tar.gz$"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_createUniqueFilename_: Don't confuse existing numbers" {
|
||||||
touch "test-2.txt"
|
touch "test-2.txt"
|
||||||
|
|
||||||
run _uniqueFileName_ "test-2.txt"
|
run _createUniqueFilename_ "test-2.txt"
|
||||||
assert_output --regexp ".*/test-2\.txt\.1$"
|
assert_output --regexp ".*/test-2\.txt\.1$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: User specified separator" {
|
@test "_createUniqueFilename_: User specified separator" {
|
||||||
touch "test.txt"
|
touch "test.txt"
|
||||||
|
|
||||||
run _uniqueFileName_ "test.txt" " "
|
run _createUniqueFilename_ "test.txt" " "
|
||||||
assert_output --regexp ".*/test\.txt 1$"
|
assert_output --regexp ".*/test\.txt 1$"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_uniqueFileName_: failure" {
|
@test "_createUniqueFilename_: failure" {
|
||||||
run _uniqueFileName_
|
run _createUniqueFilename_
|
||||||
|
|
||||||
assert_failure
|
assert_failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "_fileName_: with extension" {
|
||||||
|
run _fileName_ "./path/to/file/test.txt"
|
||||||
|
assert_success
|
||||||
|
assert_output "test.txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileName_: without extension" {
|
||||||
|
run _fileName_ "path/to/file/test"
|
||||||
|
assert_success
|
||||||
|
assert_output "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileBasename_" {
|
||||||
|
run _fileBasename_ "path/to/file/test.txt"
|
||||||
|
assert_success
|
||||||
|
assert_output "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileExtension_: simple extension" {
|
||||||
|
run _fileExtension_ "path/to/file/test.txt"
|
||||||
|
assert_success
|
||||||
|
assert_output "txt"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileExtension_: no extension" {
|
||||||
|
run _fileExtension_ "path/to/file/test"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileExtension_: two level extension" {
|
||||||
|
run _fileExtension_ "path/to/file/test.tar.bz2"
|
||||||
|
assert_success
|
||||||
|
assert_output "tar.bz2"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileDirectory_" {
|
||||||
|
run _fileDirectory_ "path/to/file/test.txt"
|
||||||
|
assert_success
|
||||||
|
assert_output "path/to/file"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileAbsPath_: file" {
|
||||||
|
touch "./test.txt"
|
||||||
|
run _fileAbsPath_ "./test.txt"
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp "/.*/files\.bats.*/test\.txt$"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileAbsPath_: directory" {
|
||||||
|
mkdir "./testdir"
|
||||||
|
run _fileAbsPath_ "./testdir"
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp "/.*/files\.bats.*/testdir$"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileAbsPath_: fail when not found" {
|
||||||
|
run _fileAbsPath_ "./test.txt"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileContains_: No match" {
|
||||||
|
echo "some text" > "./test.txt"
|
||||||
|
run _fileContains_ "./test.txt" "nothing here"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_fileContains_: Pattern matched" {
|
||||||
|
echo "some text" > "./test.txt"
|
||||||
|
run _fileContains_ "./test.txt" "some*"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
_testBackupFile_
|
_testBackupFile_
|
||||||
_testListFiles_
|
_testListFiles_
|
||||||
_testParseFilename_
|
_testParseFilename_
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ load 'test_helper/bats-assert/load'
|
|||||||
|
|
||||||
######## SETUP TESTS ########
|
######## SETUP TESTS ########
|
||||||
ROOTDIR="$(git rev-parse --show-toplevel)"
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
SOURCEFILE="${ROOTDIR}/utilities/baseHelpers.bash"
|
SOURCEFILE="${ROOTDIR}/utilities/misc.bash"
|
||||||
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
if test -f "${SOURCEFILE}" >&2; then
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
@@ -67,18 +67,6 @@ teardown() {
|
|||||||
assert_output ""
|
assert_output ""
|
||||||
}
|
}
|
||||||
|
|
||||||
_testCheckBinary_() {
|
|
||||||
@test "_checkBinary_: true" {
|
|
||||||
run _checkBinary_ "vi"
|
|
||||||
assert_success
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_checkBinary_: false" {
|
|
||||||
run _checkBinary_ "someNonexistantBinary"
|
|
||||||
assert_failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_testExecute_() {
|
_testExecute_() {
|
||||||
@test "_execute_: Debug command" {
|
@test "_execute_: Debug command" {
|
||||||
DRYRUN=true
|
DRYRUN=true
|
||||||
@@ -91,7 +79,7 @@ _testExecute_() {
|
|||||||
run _execute_
|
run _execute_
|
||||||
|
|
||||||
assert_failure
|
assert_failure
|
||||||
assert_output --regexp "_execute_ needs a command$"
|
assert_output --regexp "\[ fatal\] Missing required argument to _execute_"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_execute_: Bad command" {
|
@test "_execute_: Bad command" {
|
||||||
@@ -167,97 +155,65 @@ _testExecute_() {
|
|||||||
assert_file_not_exist "testfile.txt"
|
assert_file_not_exist "testfile.txt"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_testFindBaseDirectory_() {
|
|
||||||
@test "_findBaseDir_" {
|
|
||||||
run _findBaseDir_
|
|
||||||
assert_output --regexp "^/usr/local/Cellar/bats-core/[0-9]\.[0-9]\.[0-9]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_testHaveFunction_() {
|
|
||||||
|
|
||||||
@test "_haveFunction_: Success" {
|
|
||||||
run _haveFunction_ "_haveFunction_"
|
|
||||||
|
|
||||||
assert_success
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_haveFunction_: Failure" {
|
|
||||||
run _haveFunction_ "_someUndefinedFunction_"
|
|
||||||
|
|
||||||
assert_failure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_testProgressBar_() {
|
|
||||||
@test "_progressBar_: verbose" {
|
|
||||||
verbose=true
|
|
||||||
run _progressBar_ 100
|
|
||||||
|
|
||||||
assert_success
|
|
||||||
assert_output ""
|
|
||||||
verbose=false
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_progressBar_: quiet" {
|
|
||||||
quiet=true
|
|
||||||
run _progressBar_ 100
|
|
||||||
|
|
||||||
assert_success
|
|
||||||
assert_output ""
|
|
||||||
quiet=false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_testSeekConfirmation_() {
|
|
||||||
@test "_seekConfirmation_: yes" {
|
|
||||||
run _seekConfirmation_ 'test' <<<"y"
|
|
||||||
|
|
||||||
assert_success
|
|
||||||
assert_output --partial "[ input] test"
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_seekConfirmation_: no" {
|
|
||||||
run _seekConfirmation_ 'test' <<<"n"
|
|
||||||
|
|
||||||
assert_failure
|
|
||||||
assert_output --partial "[ input] test"
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_seekConfirmation_: Force" {
|
|
||||||
FORCE=true
|
|
||||||
|
|
||||||
run _seekConfirmation_ "test"
|
|
||||||
assert_success
|
|
||||||
assert_output --partial "test"
|
|
||||||
}
|
|
||||||
|
|
||||||
@test "_seekConfirmation_: Quiet" {
|
|
||||||
QUIET=true
|
|
||||||
run _seekConfirmation_ 'test' <<<"y"
|
|
||||||
|
|
||||||
assert_success
|
|
||||||
refute_output --partial "test"
|
|
||||||
|
|
||||||
quiet=false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_testSetPATH_() {
|
|
||||||
@test "_setPATH_" {
|
|
||||||
mkdir -p "${TESTDIR}/testing/from/bats"
|
|
||||||
_setPATH_ "${TESTDIR}/testing/from/bats" "${TESTDIR}/testing/again"
|
|
||||||
run echo "${PATH}"
|
|
||||||
assert_output --regexp "/testing/from/bats"
|
|
||||||
refute_output --regexp "/testing/again"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_testCheckBinary_
|
|
||||||
_testExecute_
|
_testExecute_
|
||||||
_testFindBaseDirectory_
|
|
||||||
_testHaveFunction_
|
@test "_findBaseDir_" {
|
||||||
_testProgressBar_
|
run _findBaseDir_
|
||||||
_testSeekConfirmation_
|
assert_output --regexp "^/usr/local/Cellar/bats-core/[0-9]\.[0-9]\.[0-9]"
|
||||||
_testSetPATH_
|
}
|
||||||
|
|
||||||
|
@test "_generateUUID_" {
|
||||||
|
run _generateUUID_
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_makeProgressBar_: verbose" {
|
||||||
|
verbose=true
|
||||||
|
run _makeProgressBar_ 100
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_output ""
|
||||||
|
verbose=false
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_makeProgressBar_: quiet" {
|
||||||
|
quiet=true
|
||||||
|
run _makeProgressBar_ 100
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_output ""
|
||||||
|
quiet=false
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_seekConfirmation_: yes" {
|
||||||
|
run _seekConfirmation_ 'test' <<<"y"
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "[ input] test"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_seekConfirmation_: no" {
|
||||||
|
run _seekConfirmation_ 'test' <<<"n"
|
||||||
|
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "[ input] test"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_seekConfirmation_: Force" {
|
||||||
|
FORCE=true
|
||||||
|
|
||||||
|
run _seekConfirmation_ "test"
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "test"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_seekConfirmation_: Quiet" {
|
||||||
|
QUIET=true
|
||||||
|
run _seekConfirmation_ 'test' <<<"y"
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
refute_output --partial "test"
|
||||||
|
|
||||||
|
quiet=false
|
||||||
|
}
|
||||||
@@ -47,11 +47,11 @@ teardown() {
|
|||||||
run $s -K
|
run $s -K
|
||||||
|
|
||||||
assert_failure
|
assert_failure
|
||||||
assert_output --partial "[ fatal] invalid option: '-K'"
|
assert_output --partial "[ fatal] invalid option: -K"
|
||||||
assert_file_exist "${TESTDIR}/logs/log.txt"
|
assert_file_exist "${TESTDIR}/logs/log.txt"
|
||||||
|
|
||||||
run cat "${TESTDIR}/logs/log.txt"
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
assert_line --index 0 --regexp "\[ fatal\] .* invalid option: '-K'\. \(.*"
|
assert_line --index 0 --regexp "\[ fatal\] .* invalid option: -K \(.*"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "success" {
|
@test "success" {
|
||||||
|
|||||||
128
test/standaloneTemplate.bats
Executable file
128
test/standaloneTemplate.bats
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load 'test_helper/bats-support/load'
|
||||||
|
load 'test_helper/bats-file/load'
|
||||||
|
load 'test_helper/bats-assert/load'
|
||||||
|
|
||||||
|
######## SETUP TESTS ########
|
||||||
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
|
s="${ROOTDIR}/standaloneTemplate.sh"
|
||||||
|
|
||||||
|
if [ -f "${s}" ]; then
|
||||||
|
base="$(basename "${s}")"
|
||||||
|
else
|
||||||
|
printf "No executable '${s}' found.\n" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
TESTDIR="$(temp_make)"
|
||||||
|
curPath="${PWD}"
|
||||||
|
|
||||||
|
BATSLIB_FILE_PATH_REM="#${TEST_TEMP_DIR}"
|
||||||
|
BATSLIB_FILE_PATH_ADD='<temp>'
|
||||||
|
|
||||||
|
s="$s --logfile=${TESTDIR}/logs/log.txt" # Logs go to temp directory
|
||||||
|
|
||||||
|
pushd "${TESTDIR}" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
popd >&2
|
||||||
|
temp_del "${TESTDIR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
######## RUN TESTS ##########
|
||||||
|
@test "sanity" {
|
||||||
|
run true
|
||||||
|
assert_success
|
||||||
|
assert [ "$output" = "" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Fail - fail on bad args and create logfile" {
|
||||||
|
run $s -K
|
||||||
|
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "[ fatal] invalid option: -K"
|
||||||
|
assert_file_exist "${TESTDIR}/logs/log.txt"
|
||||||
|
|
||||||
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
|
assert_line --index 0 --regexp "\[ fatal\] .* invalid option: -K \(.*"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "success" {
|
||||||
|
run $s
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "[ info] This is info text"
|
||||||
|
assert_output --partial "[ notice] This is notice text"
|
||||||
|
assert_output --partial "[ dryrun] This is dryrun text"
|
||||||
|
assert_output --partial "[warning] This is warning text"
|
||||||
|
assert_output --partial "[ error] This is error text"
|
||||||
|
assert_output --partial "[success] This is success text"
|
||||||
|
assert_output --partial "[ input] This is input text"
|
||||||
|
|
||||||
|
assert_file_exist "${TESTDIR}/logs/log.txt"
|
||||||
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
|
assert_line --index 0 --regexp "\[ error\] \[.*\] This is error text \( _mainScript_:standaloneTemplate.* \)"
|
||||||
|
assert_line --index 1 ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "success and INFO level log" {
|
||||||
|
run $s --loglevel=INFO
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "[ info] This is info text"
|
||||||
|
|
||||||
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
|
assert_line --index 0 --regexp "\[ info\].*This is info text"
|
||||||
|
assert_line --index 1 --regexp "\[ notice\].*This is notice text"
|
||||||
|
assert_line --index 2 --regexp "\[warning\].*This is warning text"
|
||||||
|
assert_line --index 3 --regexp "\[ error\].*This is error text"
|
||||||
|
assert_line --index 4 --regexp "\[success\].*This is success text"
|
||||||
|
assert_line --index 5 ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "success and NOTICE level log" {
|
||||||
|
run $s --loglevel=NOTICE
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "[ info] This is info text"
|
||||||
|
|
||||||
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
|
assert_line --index 0 --regexp "\[ notice\].*This is notice text"
|
||||||
|
assert_line --index 1 --regexp "\[warning\].*This is warning text"
|
||||||
|
assert_line --index 2 --regexp "\[ error\].*This is error text"
|
||||||
|
assert_line --index 3 --regexp "\[success\].*This is success text"
|
||||||
|
assert_line --index 4 ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Usage (-h)" {
|
||||||
|
run $s -h
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_line --partial --index 0 "$base [OPTION]... [FILE]..."
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Usage (--help)" {
|
||||||
|
run $s --help
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_line --partial --index 0 "$base [OPTION]... [FILE]..."
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "quiet (-q)" {
|
||||||
|
run $s -q --loglevel=INFO
|
||||||
|
assert_success
|
||||||
|
assert_output ""
|
||||||
|
|
||||||
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
|
run cat "${TESTDIR}/logs/log.txt"
|
||||||
|
assert_line --index 0 --regexp "\[ info\].*This is info text"
|
||||||
|
assert_line --index 1 --regexp "\[ notice\].*This is notice text"
|
||||||
|
assert_line --index 2 --regexp "\[warning\].*This is warning text"
|
||||||
|
assert_line --index 3 --regexp "\[ error\].*This is error text"
|
||||||
|
assert_line --index 4 --regexp "\[success\].*This is success text"
|
||||||
|
assert_line --index 5 ""
|
||||||
|
}
|
||||||
@@ -7,8 +7,8 @@ load 'test_helper/bats-assert/load'
|
|||||||
|
|
||||||
######## SETUP TESTS ########
|
######## SETUP TESTS ########
|
||||||
ROOTDIR="$(git rev-parse --show-toplevel)"
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
SOURCEFILE="${ROOTDIR}/utilities/textProcessing.bash"
|
SOURCEFILE="${ROOTDIR}/utilities/strings.bash"
|
||||||
BASEHELPERS="${ROOTDIR}/utilities/baseHelpers.bash"
|
BASEHELPERS="${ROOTDIR}/utilities/misc.bash"
|
||||||
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
if test -f "${SOURCEFILE}" >&2; then
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
@@ -76,6 +76,35 @@ teardown() {
|
|||||||
assert_output ""
|
assert_output ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "_splitString_" {
|
||||||
|
run _splitString_ "a,b,cd" ","
|
||||||
|
assert_success
|
||||||
|
assert_line --index 0 "a"
|
||||||
|
assert_line --index 1 "b"
|
||||||
|
assert_line --index 2 "cd"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_stringContains_: success" {
|
||||||
|
run _stringContains_ "hello world!" "lo"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_stringContains_: failure" {
|
||||||
|
run _stringContains_ "hello world!" "zebra"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_stringRegex_: success" {
|
||||||
|
run _stringRegex_ "hello world!" "[a-z].*!$"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_stringRegex_: failure" {
|
||||||
|
run _stringRegex_ "hello world!" "^.*[0-9]+"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_testCleanString_() {
|
_testCleanString_() {
|
||||||
|
|
||||||
@test "_cleanString_: fail" {
|
@test "_cleanString_: fail" {
|
||||||
@@ -160,46 +189,46 @@ _testCleanString_
|
|||||||
|
|
||||||
_testStopWords_() {
|
_testStopWords_() {
|
||||||
|
|
||||||
@test "_stopWords_: success" {
|
@test "_stripStopwords_: success" {
|
||||||
run _stopWords_ "A string to be parsed"
|
run _stripStopwords_ "A string to be parsed"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "string parsed"
|
assert_output "string parsed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_stopWords_: success w/ user terms" {
|
@test "_stripStopwords_: success w/ user terms" {
|
||||||
run _stopWords_ "A string to be parsed to help pass this test being performed by bats" "bats,string"
|
run _stripStopwords_ "A string to be parsed to help pass this test being performed by bats" "bats,string"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "parsed pass performed"
|
assert_output "parsed pass performed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_stopWords_: No changes" {
|
@test "_stripStopwords_: No changes" {
|
||||||
run _stopWords_ "string parsed pass performed"
|
run _stripStopwords_ "string parsed pass performed"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "string parsed pass performed"
|
assert_output "string parsed pass performed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_stopWords_: fail" {
|
@test "_stripStopwords_: fail" {
|
||||||
run _stopWords_
|
run _stripStopwords_
|
||||||
assert_failure
|
assert_failure
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
_testStopWords_
|
_testStopWords_
|
||||||
|
|
||||||
@test "_escape_" {
|
@test "_escapeString_" {
|
||||||
run _escape_ "Here is some / text to & be - escaped"
|
run _escapeString_ "Here is some / text to & be - escaped"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "Here\ is\ some\ /\ text\ to\ &\ be\ -\ escaped"
|
assert_output "Here\ is\ some\ /\ text\ to\ &\ be\ -\ escaped"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_htmlEncode_" {
|
@test "_encodeHTML_" {
|
||||||
run _htmlEncode_ "Here's some text& to > be h?t/M(l• en™code磧¶d"
|
run _encodeHTML_ "Here's some text& to > be h?t/M(l• en™code磧¶d"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "Here's some text& to > be h?t/M(l• en™code磧¶d"
|
assert_output "Here's some text& to > be h?t/M(l• en™code磧¶d"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_htmlDecode_" {
|
@test "_decodeHTML_" {
|
||||||
run _htmlDecode_ "♣Here's some text & to > be h?t/M(l• en™code磧¶d"
|
run _decodeHTML_ "♣Here's some text & to > be h?t/M(l• en™code磧¶d"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "♣Here's some text & to > be h?t/M(l• en™code磧¶d"
|
assert_output "♣Here's some text & to > be h?t/M(l• en™code磧¶d"
|
||||||
}
|
}
|
||||||
@@ -232,27 +261,27 @@ _testStopWords_
|
|||||||
assert_output "MAKE THIS UPPERCASE"
|
assert_output "MAKE THIS UPPERCASE"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_urlEncode_" {
|
@test "_encodeURL_" {
|
||||||
run _urlEncode_ "Here's some.text%that&needs_to-be~encoded+a*few@more(characters)"
|
run _encodeURL_ "Here's some.text%that&needs_to-be~encoded+a*few@more(characters)"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "Here%27s%20some.text%25that%26needs_to-be~encoded%2Ba%2Afew%40more%28characters%29"
|
assert_output "Here%27s%20some.text%25that%26needs_to-be~encoded%2Ba%2Afew%40more%28characters%29"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_urlDecode_" {
|
@test "_decodeURL_" {
|
||||||
run _urlDecode_ "Here%27s%20some.text%25that%26needs_to-be~encoded%2Ba%2Afew%40more%28characters%29"
|
run _decodeURL_ "Here%27s%20some.text%25that%26needs_to-be~encoded%2Ba%2Afew%40more%28characters%29"
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "Here's some.text%that&needs_to-be~encoded+a*few@more(characters)"
|
assert_output "Here's some.text%that&needs_to-be~encoded+a*few@more(characters)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_regex_: success" {
|
@test "_regexCapture_: success" {
|
||||||
run _regex_ "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$' || echo "no match found"
|
run _regexCapture_ "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$' || echo "no match found"
|
||||||
|
|
||||||
assert_success
|
assert_success
|
||||||
assert_output "#FFFFFF"
|
assert_output "#FFFFFF"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "_regex_: failure" {
|
@test "_regexCapture_: failure" {
|
||||||
run _regex_ "gggggg" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
run _regexCapture_ "gggggg" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
||||||
|
|
||||||
assert_failure
|
assert_failure
|
||||||
}
|
}
|
||||||
93
test/template_utils.bats
Executable file
93
test/template_utils.bats
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
#shellcheck disable
|
||||||
|
|
||||||
|
load 'test_helper/bats-support/load'
|
||||||
|
load 'test_helper/bats-file/load'
|
||||||
|
load 'test_helper/bats-assert/load'
|
||||||
|
|
||||||
|
######## SETUP TESTS ########
|
||||||
|
ROOTDIR="$(git rev-parse --show-toplevel)"
|
||||||
|
SOURCEFILE="${ROOTDIR}/utilities/template_utils.bash"
|
||||||
|
ALERTS="${ROOTDIR}/utilities/alerts.bash"
|
||||||
|
|
||||||
|
if test -f "${SOURCEFILE}" >&2; then
|
||||||
|
source "${SOURCEFILE}"
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${SOURCEFILE}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "${ALERTS}" >&2; then
|
||||||
|
source "${ALERTS}"
|
||||||
|
_setColors_ #Set color constants
|
||||||
|
else
|
||||||
|
echo "Sourcefile not found: ${ALERTS}" >&2
|
||||||
|
printf "Can not run tests.\n" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
|
||||||
|
TESTDIR="$(temp_make)"
|
||||||
|
curPath="${PWD}"
|
||||||
|
|
||||||
|
BATSLIB_FILE_PATH_REM="#${TEST_TEMP_DIR}"
|
||||||
|
BATSLIB_FILE_PATH_ADD='<temp>'
|
||||||
|
|
||||||
|
pushd "${TESTDIR}" >&2
|
||||||
|
|
||||||
|
######## DEFAULT FLAGS ########
|
||||||
|
LOGFILE="${TESTDIR}/logs/log.txt"
|
||||||
|
QUIET=false
|
||||||
|
LOGLEVEL=ERROR
|
||||||
|
VERBOSE=false
|
||||||
|
FORCE=false
|
||||||
|
DRYRUN=false
|
||||||
|
|
||||||
|
set -o errtrace
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
set +o nounset
|
||||||
|
set +o errtrace
|
||||||
|
set +o pipefail
|
||||||
|
|
||||||
|
popd >&2
|
||||||
|
temp_del "${TESTDIR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
######## RUN TESTS ########
|
||||||
|
@test "Sanity..." {
|
||||||
|
run true
|
||||||
|
|
||||||
|
assert_success
|
||||||
|
assert_output ""
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_setPATH_: fail on dir not found" {
|
||||||
|
mkdir -p "${TESTDIR}/testing/from/bats"
|
||||||
|
mkdir -p "${TESTDIR}/testing/from/bats_again"
|
||||||
|
run _setPATH_ "${TESTDIR}/testing/from/bats" "${TESTDIR}/testing/again" "${TESTDIR}/testing/from/bats_again"
|
||||||
|
assert_failure
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_setPATH_: success" {
|
||||||
|
mkdir -p "${TESTDIR}/testing/from/bats"
|
||||||
|
mkdir -p "${TESTDIR}/testing/from/bats_again"
|
||||||
|
_setPATH_ "${TESTDIR}/testing/from/bats" "${TESTDIR}/testing/from/bats_again"
|
||||||
|
|
||||||
|
run echo "${PATH}"
|
||||||
|
assert_output --regexp "/testing/from/bats"
|
||||||
|
refute_output --regexp "/testing/again"
|
||||||
|
assert_output --regexp "/testing/from/bats_again"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "_makeTempDir_" {
|
||||||
|
VERBOSE=true
|
||||||
|
run _makeTempDir_
|
||||||
|
assert_success
|
||||||
|
assert_output --regexp "\\\$TMP_DIR=/.*\.[0-9]+\.[0-9]+\.[0-9]+$"
|
||||||
|
}
|
||||||
@@ -1,16 +1,22 @@
|
|||||||
_setColors_() {
|
# Functions for providing alerts to the user and logging them
|
||||||
# DESC: Sets colors use for alerts.
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: echo "${blue}Some text${reset}"
|
|
||||||
|
|
||||||
if tput setaf 1 &>/dev/null; then
|
_setColors_() {
|
||||||
|
# DESC:
|
||||||
|
# Sets colors use for alerts.
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# echo "${blue}Some text${reset}"
|
||||||
|
|
||||||
|
if tput setaf 1 >/dev/null 2>&1; then
|
||||||
bold=$(tput bold)
|
bold=$(tput bold)
|
||||||
underline=$(tput smul)
|
underline=$(tput smul)
|
||||||
reverse=$(tput rev)
|
reverse=$(tput rev)
|
||||||
reset=$(tput sgr0)
|
reset=$(tput sgr0)
|
||||||
|
|
||||||
if [[ $(tput colors) -ge 256 ]] 2>/dev/null; then
|
if [[ $(tput colors) -ge 256 ]] >/dev/null 2>&1; then
|
||||||
white=$(tput setaf 231)
|
white=$(tput setaf 231)
|
||||||
blue=$(tput setaf 38)
|
blue=$(tput setaf 38)
|
||||||
yellow=$(tput setaf 11)
|
yellow=$(tput setaf 11)
|
||||||
@@ -46,68 +52,75 @@ _setColors_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_alert_() {
|
_alert_() {
|
||||||
# DESC: Controls all printing of messages to log files and stdout.
|
# DESC:
|
||||||
# ARGS: $1 (required) - The type of alert to print
|
# 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,
|
# (success, header, notice, dryrun, debug, warning, error,
|
||||||
# fatal, info, input)
|
# fatal, info, input)
|
||||||
# $2 (required) - The message to be printed to stdout and/or a log file
|
# $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
|
# $3 (optional) - Pass '${LINENO}' to print the line number where the _alert_ was triggered
|
||||||
# OUTS: None
|
# OUTS:
|
||||||
# USAGE: [ALERTTYPE] "[MESSAGE]" "${LINENO}"
|
# stdout: The message is printed to stdout
|
||||||
# NOTES: The colors of each alert type are set in this function
|
# log file: The message is printed to a log file
|
||||||
# For specified alert types, the funcstac will be printed
|
# 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 _color
|
||||||
local alertType="${1}"
|
local _alertType="${1}"
|
||||||
local message="${2}"
|
local _message="${2}"
|
||||||
local line="${3:-}" # Optional line number
|
local _line="${3:-}" # Optional line number
|
||||||
|
|
||||||
if [[ -n ${line} && ${alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
[[ $# -lt 2 ]] && fatal 'Missing required argument to _alert_'
|
||||||
message="${message} (line: ${line}) $(_functionStack_)"
|
|
||||||
elif [[ -n ${line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
if [[ -n ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
message="${message} (line: ${line})"
|
_message="${_message} ${gray}(line: ${_line}) $(_printFuncStack_)"
|
||||||
elif [[ -z ${line} && ${alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
elif [[ -n ${_line} && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
message="${message} $(_functionStack_)"
|
_message="${_message} ${gray}(line: ${_line})"
|
||||||
|
elif [[ -z ${_line} && ${_alertType} =~ ^(fatal|error) && ${FUNCNAME[2]} != "_trapCleanup_" ]]; then
|
||||||
|
_message="${_message} ${gray}$(_printFuncStack_)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${alertType} =~ ^(error|fatal) ]]; then
|
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||||
color="${bold}${red}"
|
_color="${bold}${red}"
|
||||||
elif [ "${alertType}" == "info" ]; then
|
elif [ "${_alertType}" == "info" ]; then
|
||||||
color="${gray}"
|
_color="${gray}"
|
||||||
elif [ "${alertType}" == "warning" ]; then
|
elif [ "${_alertType}" == "warning" ]; then
|
||||||
color="${red}"
|
_color="${red}"
|
||||||
elif [ "${alertType}" == "success" ]; then
|
elif [ "${_alertType}" == "success" ]; then
|
||||||
color="${green}"
|
_color="${green}"
|
||||||
elif [ "${alertType}" == "debug" ]; then
|
elif [ "${_alertType}" == "debug" ]; then
|
||||||
color="${purple}"
|
_color="${purple}"
|
||||||
elif [ "${alertType}" == "header" ]; then
|
elif [ "${_alertType}" == "header" ]; then
|
||||||
color="${bold}${tan}"
|
_color="${bold}${white}${underline}"
|
||||||
elif [ ${alertType} == "notice" ]; then
|
elif [ ${_alertType} == "notice" ]; then
|
||||||
color="${bold}"
|
_color="${bold}"
|
||||||
elif [ ${alertType} == "input" ]; then
|
elif [ ${_alertType} == "input" ]; then
|
||||||
color="${bold}${underline}"
|
_color="${bold}${underline}"
|
||||||
elif [ "${alertType}" = "dryrun" ]; then
|
elif [ "${_alertType}" = "dryrun" ]; then
|
||||||
color="${blue}"
|
_color="${blue}"
|
||||||
else
|
else
|
||||||
color=""
|
_color=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_writeToScreen_() {
|
_writeToScreen_() {
|
||||||
|
|
||||||
("${QUIET}") && return 0 # Print to console when script is not 'quiet'
|
("${QUIET}") && return 0 # Print to console when script is not 'quiet'
|
||||||
[[ ${VERBOSE} == false && ${alertType} =~ ^(debug|verbose) ]] && return 0
|
[[ ${VERBOSE} == false && ${_alertType} =~ ^(debug|verbose) ]] && return 0
|
||||||
|
|
||||||
if ! [[ -t 1 ]]; then # Don't use colors on non-recognized terminals
|
if ! [[ -t 1 || -z ${TERM:-} ]]; then # Don't use colors on non-recognized terminals
|
||||||
color=""
|
_color=""
|
||||||
reset=""
|
reset=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "$(date +"%r") ${color}$(printf "[%7s]" "${alertType}") ${message}${reset}"
|
printf "%s ${_color}[%7s] %s${reset}\n" "$(date +"%r")" "${_alertType}" "${_message}"
|
||||||
}
|
}
|
||||||
_writeToScreen_
|
_writeToScreen_
|
||||||
|
|
||||||
_writeToLog_() {
|
_writeToLog_() {
|
||||||
[[ ${alertType} == "input" ]] && return 0
|
[[ ${_alertType} == "input" ]] && return 0
|
||||||
[[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0
|
[[ ${LOGLEVEL} =~ (off|OFF|Off) ]] && return 0
|
||||||
if [ -z "${LOGFILE:-}" ]; then
|
if [ -z "${LOGFILE:-}" ]; then
|
||||||
LOGFILE="$(pwd)/$(basename "$0").log"
|
LOGFILE="$(pwd)/$(basename "$0").log"
|
||||||
@@ -116,12 +129,9 @@ _alert_() {
|
|||||||
[[ ! -f ${LOGFILE} ]] && touch "${LOGFILE}"
|
[[ ! -f ${LOGFILE} ]] && touch "${LOGFILE}"
|
||||||
|
|
||||||
# Don't use colors in logs
|
# Don't use colors in logs
|
||||||
if command -v gsed &>/dev/null; then
|
local cleanmessage="$(echo "${_message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
|
||||||
local cleanmessage="$(echo "${message}" | gsed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
|
# Print message to log file
|
||||||
else
|
printf "%s [%7s] %s %s\n" "$(date +"%b %d %R:%S")" "${_alertType}" "[$(/bin/hostname)]" "${cleanmessage}" >>"${LOGFILE}"
|
||||||
local cleanmessage="$(echo "${message}" | sed -E 's/(\x1b)?\[(([0-9]{1,2})(;[0-9]{1,3}){0,2})?[mGK]//g')"
|
|
||||||
fi
|
|
||||||
echo -e "$(date +"%b %d %R:%S") $(printf "[%7s]" "${alertType}") [$(/bin/hostname)] ${cleanmessage}" >>"${LOGFILE}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Write specified log level data to logfile
|
# Write specified log level data to logfile
|
||||||
@@ -133,27 +143,27 @@ _alert_() {
|
|||||||
_writeToLog_
|
_writeToLog_
|
||||||
;;
|
;;
|
||||||
INFO | info | Info)
|
INFO | info | Info)
|
||||||
if [[ ${alertType} =~ ^(die|error|fatal|warning|info|notice|success) ]]; then
|
if [[ ${_alertType} =~ ^(error|fatal|warning|info|notice|success) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
NOTICE | notice | Notice)
|
NOTICE | notice | Notice)
|
||||||
if [[ ${alertType} =~ ^(die|error|fatal|warning|notice|success) ]]; then
|
if [[ ${_alertType} =~ ^(error|fatal|warning|notice|success) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
WARN | warn | Warn)
|
WARN | warn | Warn)
|
||||||
if [[ ${alertType} =~ ^(die|error|fatal|warning) ]]; then
|
if [[ ${_alertType} =~ ^(error|fatal|warning) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
ERROR | error | Error)
|
ERROR | error | Error)
|
||||||
if [[ ${alertType} =~ ^(die|error|fatal) ]]; then
|
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
FATAL | fatal | Fatal)
|
FATAL | fatal | Fatal)
|
||||||
if [[ ${alertType} =~ ^(die|fatal) ]]; then
|
if [[ ${_alertType} =~ ^fatal ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -161,7 +171,7 @@ _alert_() {
|
|||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
if [[ ${alertType} =~ ^(die|error|fatal) ]]; then
|
if [[ ${_alertType} =~ ^(error|fatal) ]]; then
|
||||||
_writeToLog_
|
_writeToLog_
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -176,30 +186,117 @@ info() { _alert_ info "${1}" "${2:-}"; }
|
|||||||
success() { _alert_ success "${1}" "${2:-}"; }
|
success() { _alert_ success "${1}" "${2:-}"; }
|
||||||
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
dryrun() { _alert_ dryrun "${1}" "${2:-}"; }
|
||||||
input() { _alert_ input "${1}" "${2:-}"; }
|
input() { _alert_ input "${1}" "${2:-}"; }
|
||||||
header() { _alert_ header "== ${1} ==" "${2:-}"; }
|
header() { _alert_ header "${1}" "${2:-}"; }
|
||||||
debug() { _alert_ debug "${1}" "${2:-}"; }
|
debug() { _alert_ debug "${1}" "${2:-}"; }
|
||||||
die() {
|
|
||||||
_alert_ fatal "${1}" "${2:-}"
|
|
||||||
_safeExit_ "1"
|
|
||||||
}
|
|
||||||
fatal() {
|
fatal() {
|
||||||
_alert_ fatal "${1}" "${2:-}"
|
_alert_ fatal "${1}" "${2:-}"
|
||||||
_safeExit_ "1"
|
_safeExit_ "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
_functionStack_() {
|
_printFuncStack_() {
|
||||||
# DESC: Prints the function stack in use
|
# DESC:
|
||||||
# ARGS: None
|
# Prints the function stack in use. Used for debugging, and error reporting.
|
||||||
# OUTS: Prints [function]:[file]:[line]
|
# ARGS:
|
||||||
# NOTE: Does not print functions from the alert class
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints [function]:[file]:[line]
|
||||||
|
# NOTE:
|
||||||
|
# Does not print functions from the alert class
|
||||||
local _i
|
local _i
|
||||||
funcStackResponse=()
|
_funcStackResponse=()
|
||||||
for ((_i = 1; _i < ${#BASH_SOURCE[@]}; _i++)); do
|
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
|
case "${FUNCNAME[$_i]}" in "_alert_" | "_trapCleanup_" | fatal | error | warning | notice | info | debug | dryrun | header | success) continue ;; esac
|
||||||
funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
|
_funcStackResponse+=("${FUNCNAME[$_i]}:$(basename ${BASH_SOURCE[$_i]}):${BASH_LINENO[_i - 1]}")
|
||||||
done
|
done
|
||||||
printf "( "
|
printf "( "
|
||||||
printf %s "${funcStackResponse[0]}"
|
printf %s "${_funcStackResponse[0]}"
|
||||||
printf ' < %s' "${funcStackResponse[@]:1}"
|
printf ' < %s' "${_funcStackResponse[@]:1}"
|
||||||
printf ' )\n'
|
printf ' )\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_centerOutput_() {
|
||||||
|
# DESC:
|
||||||
|
# Prints text centered in the terminal window with an optional fill character
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Text to center
|
||||||
|
# $2 (optional): Fill character
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Failure
|
||||||
|
# stdout:
|
||||||
|
# USAGE:
|
||||||
|
# _centerOutput_ "Text to print in the center" "-"
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _input="${1}"
|
||||||
|
local _symbol="${2:- }"
|
||||||
|
local _filler
|
||||||
|
local _out
|
||||||
|
local _no_ansi_out
|
||||||
|
local i
|
||||||
|
|
||||||
|
_no_ansi_out=$(_stripANSI_ "${_input}")
|
||||||
|
declare -i _str_len=${#_no_ansi_out}
|
||||||
|
declare -i _filler_len="$(((COLUMNS - _str_len) / 2))"
|
||||||
|
|
||||||
|
[[ -n ${_symbol} ]] && _symbol="${_symbol:0:1}"
|
||||||
|
for ((i = 0; i < _filler_len; i++)); do
|
||||||
|
_filler+="${_symbol}"
|
||||||
|
done
|
||||||
|
|
||||||
|
_out="${_filler}${_input}${_filler}"
|
||||||
|
[[ $(((COLUMNS - _str_len) % 2)) -ne 0 ]] && _out+="${_symbol}"
|
||||||
|
printf "%s\n" "${_out}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_columnizeOutput_() {
|
||||||
|
# DESC:
|
||||||
|
# Creates a column output for key/value pairs with line wrapping for the right column (value). Attempts to wrap at a sane line length (~100 cols) on larger screens.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Left padding of table
|
||||||
|
# $2 (required): Width of first column
|
||||||
|
# $3 (required): Key name (left column text)
|
||||||
|
# $4 (required): Long value (right column text. Wraps around if too long)
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints the columnized output
|
||||||
|
# NOTE:
|
||||||
|
# Long text or ANSI colors in the first column may create display issues
|
||||||
|
# USAGE:
|
||||||
|
# _columnizeOutput_ 0 30 10 "Key" "Long value text"
|
||||||
|
|
||||||
|
[[ $# -lt 5 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _leftIndent=$1
|
||||||
|
local _leftColumn=$2
|
||||||
|
local _key="$3"
|
||||||
|
local _value="$4"
|
||||||
|
local _line
|
||||||
|
local _rightIndent
|
||||||
|
|
||||||
|
if [ "$(tput cols)" -gt 180 ]; then
|
||||||
|
_rightIndent=80
|
||||||
|
elif [ "$(tput cols)" -gt 160 ]; then
|
||||||
|
_rightIndent=60
|
||||||
|
elif [ "$(tput cols)" -gt 130 ]; then
|
||||||
|
_rightIndent=30
|
||||||
|
elif [ "$(tput cols)" -gt 120 ]; then
|
||||||
|
_rightIndent=20
|
||||||
|
elif [ "$(tput cols)" -gt 110 ]; then
|
||||||
|
_rightIndent=10
|
||||||
|
else
|
||||||
|
_rightIndent=0
|
||||||
|
fi
|
||||||
|
local _rightWrapLength=$(($(tput cols) - _leftColumn - _leftIndent - _rightIndent))
|
||||||
|
|
||||||
|
local _first_line=0
|
||||||
|
while read -r _line; do
|
||||||
|
if [[ ${_first_line} -eq 0 ]]; then
|
||||||
|
_first_line=1
|
||||||
|
else
|
||||||
|
_key=" "
|
||||||
|
fi
|
||||||
|
printf "%-${_leftIndent}s%-${_leftColumn}b %b\n" "" "${_key}" "${_line}"
|
||||||
|
done <<<"$(fold -w${_rightWrapLength} -s <<<"${_value}")"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,98 +1,450 @@
|
|||||||
|
# Functions for manipulating arrays
|
||||||
|
|
||||||
|
_dedupeArray_() {
|
||||||
|
# DESC:
|
||||||
|
# Removes duplicate array elements
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Input array
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints de-duped elements
|
||||||
|
# USAGE:
|
||||||
|
# _removeDups_ "${array[@]}"
|
||||||
|
# NOTE:
|
||||||
|
# List order may not stay the same
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/dylanaraps/pure-bash-bible
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
declare -A _tmpArray
|
||||||
|
declare -a _uniqueArray
|
||||||
|
local _i
|
||||||
|
for _i in "$@"; do
|
||||||
|
{ [[ -z ${_i} || ${_tmpArray[${_i}]:-} ]]; } && continue
|
||||||
|
_uniqueArray+=("${_i}") && _tmpArray[${_i}]=x
|
||||||
|
done
|
||||||
|
printf '%s\n' "${_uniqueArray[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_forEachDo_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates over elements and passes each to a function
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name to pass each item to
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# Return code of called function
|
||||||
|
# stdout: Output of called function
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "${arr1[@]}" | _forEachDo_ "test_func"
|
||||||
|
# _forEachDo_ "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _func="${1}"
|
||||||
|
local IFS=$'\n'
|
||||||
|
local _it
|
||||||
|
|
||||||
|
while read -r _it; do
|
||||||
|
if [[ ${_func} == *"$"* ]]; then
|
||||||
|
eval "${_func}"
|
||||||
|
else
|
||||||
|
[ ! "$(declare -f "${_func}")" ] && fatal "${FUNCNAME[0]} could not find function ${_func}"
|
||||||
|
eval "${_func}" "'${_it}'"
|
||||||
|
fi
|
||||||
|
declare -i _ret="$?"
|
||||||
|
|
||||||
|
if [[ ${_ret} -ne 0 ]]; then
|
||||||
|
return ${_ret}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_forEachValidate_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates over elements and passes each to a function for validation. Iteration stops when the function returns 1.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success)
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Iteratee function fails
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "${array[@]}" | _forEachValidate_ "_isAlpha_"
|
||||||
|
# _forEachValidate_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _func="${1}"
|
||||||
|
local IFS=$'\n'
|
||||||
|
local _it
|
||||||
|
|
||||||
|
while read -r _it; do
|
||||||
|
if [[ ${_func} == *"$"* ]]; then
|
||||||
|
eval "${_func}"
|
||||||
|
else
|
||||||
|
[ ! "$(declare -f "${_func}")" ] && fatal "${FUNCNAME[0]} could not find function ${_func}"
|
||||||
|
eval "${_func}" "'${_it}'"
|
||||||
|
fi
|
||||||
|
declare -i _ret="$?"
|
||||||
|
|
||||||
|
if [[ ${_ret} -ne 0 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_forEachFind_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates over elements, returning the first value that is validated by a function
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success)
|
||||||
|
# OUTS:
|
||||||
|
# 0 - If successful
|
||||||
|
# 1 - If iteratee function fails
|
||||||
|
# stdout: First value that is validated by the function
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "${array[@]}" | _forEachFind_ "_isAlpha_"
|
||||||
|
# _forEachFind_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
declare _func="${1}"
|
||||||
|
declare IFS=$'\n'
|
||||||
|
while read -r _it; do
|
||||||
|
|
||||||
|
if [[ ${_func} == *"$"* ]]; then
|
||||||
|
eval "${_func}"
|
||||||
|
else
|
||||||
|
eval "${_func}" "'${_it}'"
|
||||||
|
fi
|
||||||
|
declare -i _ret="$?"
|
||||||
|
if [[ ${_ret} == 0 ]]; then
|
||||||
|
printf "%s" "${_it}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_forEachFilter_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates over elements, returning only those that are validated by a function
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success)
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Failure
|
||||||
|
# stdout: Values matching the validation function
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "${array[@]}" | _forEachFind_ "_isAlpha_"
|
||||||
|
# _forEachFilter_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _func="${1}"
|
||||||
|
local IFS=$'\n'
|
||||||
|
while read -r _it; do
|
||||||
|
if [[ ${_func} == *"$"* ]]; then
|
||||||
|
eval "${_func}"
|
||||||
|
else
|
||||||
|
eval "${_func}" "'${_it}'"
|
||||||
|
fi
|
||||||
|
declare -i _ret="$?"
|
||||||
|
if [[ ${_ret} == 0 ]]; then
|
||||||
|
printf "%s\n" "${_it}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_forEachReject_() {
|
||||||
|
# DESC:
|
||||||
|
# The opposite of _forEachFilter_. Iterates over elements, returning only those that are not validated by a function
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success, 1 on failure)
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# stdout: Values NOT matching the validation function
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "${array[@]}" | _forEachReject_ "_isAlpha_"
|
||||||
|
# _forEachReject_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _func="${1}"
|
||||||
|
local IFS=$'\n'
|
||||||
|
while read -r _it; do
|
||||||
|
if [[ ${_func} == *"$"* ]]; then
|
||||||
|
eval "${_func}"
|
||||||
|
else
|
||||||
|
eval "${_func}" "'${_it}'"
|
||||||
|
fi
|
||||||
|
declare -i _ret=$?
|
||||||
|
if [[ ${_ret} -ne 0 ]]; then
|
||||||
|
echo "${_it}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_forEachSome_() {
|
||||||
|
# DESC:
|
||||||
|
# Iterates over elements, returning true if any of the elements validate as true from the function.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name to pass each item to for validation. (Must return 0 on success, 1 on failure)
|
||||||
|
# OUTS:
|
||||||
|
# 0 If match successful
|
||||||
|
# 1 If no match found
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "${array[@]}" | _forEachSome_ "_isAlpha_"
|
||||||
|
# _forEachSome_ "_isAlpha_" < <(printf "%s\n" "${array[@]}")
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _func="${1}"
|
||||||
|
local _IFS=$'\n'
|
||||||
|
while read -r _it; do
|
||||||
|
|
||||||
|
if [[ ${_func} == *"$"* ]]; then
|
||||||
|
eval "${_func}"
|
||||||
|
else
|
||||||
|
eval "${_func}" "'${_it}'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -i _ret=$?
|
||||||
|
if [[ ${_ret} -eq 0 ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
_inArray_() {
|
_inArray_() {
|
||||||
# DESC: Determine if a value is in an array
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Value to search for
|
# Determine if a value is in an array. Default is case sensitive.
|
||||||
|
# Pass -i flag to ignore case.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Value to search for
|
||||||
# $2 (Required) - Array written as ${ARRAY[@]}
|
# $2 (Required) - Array written as ${ARRAY[@]}
|
||||||
# OUTS: true/false
|
# OUTS:
|
||||||
# USAGE: if _inArray_ "VALUE" "${ARRAY[@]}"; then ...
|
# 0 if true
|
||||||
|
# 1 if untrue
|
||||||
|
# USAGE:
|
||||||
|
# if _inArray_ "VALUE" "${ARRAY[@]}"; then ...
|
||||||
|
# if _inArray_ -i "VALUE" "${ARRAY[@]}"; then ...
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
[[ $# -lt 2 ]] && fatal 'Missing required argument to _inArray_()!'
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
local value="$1"
|
local opt
|
||||||
|
local _case_insensitive=false
|
||||||
|
local OPTIND=1
|
||||||
|
while getopts ":iI" opt; do
|
||||||
|
case ${opt} in
|
||||||
|
i | I) _case_insensitive=true ;;
|
||||||
|
*) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
local _array_item
|
||||||
|
local _value="${1}"
|
||||||
shift
|
shift
|
||||||
for arrayItem in "$@"; do
|
for _array_item in "$@"; do
|
||||||
[[ ${arrayItem} == "${value}" ]] && return 0
|
if [ ${_case_insensitive} = true ]; then
|
||||||
|
_value="$(echo "${_value}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
_array_item="$(echo "${_array_item}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
fi
|
||||||
|
[[ ${_array_item} == "${_value}" ]] && return 0
|
||||||
done
|
done
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
_join_() {
|
_isEmptyArray_() {
|
||||||
# DESC: Joins items together with a user specified separator
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Separator
|
# Checks if an array is empty
|
||||||
# $@ (Required) - Items to be joined
|
# ARGS:
|
||||||
# OUTS: Prints joined terms
|
# $1 (Required) - Input array
|
||||||
|
# OUTS:
|
||||||
|
# 0 if empty
|
||||||
|
# 1 if not empty
|
||||||
# USAGE:
|
# USAGE:
|
||||||
# _join_ , a "b c" d #a,b c,d
|
# _isEmptyArray_ "${array[@]}"
|
||||||
# _join_ / var local tmp #var/local/tmp
|
# CREDIT:
|
||||||
# _join_ , "${foo[@]}" #a,b,c
|
# https://github.com/labbots/bash-utility
|
||||||
# NOTE: http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
|
|
||||||
|
|
||||||
[[ $# -lt 2 ]] && fatal 'Missing required argument to _join_()!'
|
declare -a _array=("$@")
|
||||||
|
if [ ${#_array[@]} -eq 0 ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
local IFS="${1}"
|
_joinArray_() {
|
||||||
|
# DESC:
|
||||||
|
# Joins items together with a user specified separator
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Separator
|
||||||
|
# $@ (Required) - Array or space separated items to be joined
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints joined terms
|
||||||
|
# USAGE:
|
||||||
|
# _join_ , a "b c" d #a,b c,d
|
||||||
|
# _join_ / var local tmp #var/local/tmp
|
||||||
|
# _join_ , "${foo[@]}" #a,b,c
|
||||||
|
# CREDIT:
|
||||||
|
# http://stackoverflow.com/questions/1527049/bash-join-elements-of-an-array
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _delimiter="${1}"
|
||||||
shift
|
shift
|
||||||
echo "${*}"
|
printf "%s" "${1}"
|
||||||
|
shift
|
||||||
|
printf "%s" "${@/#/${_delimiter}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
_setdiff_() {
|
_mergeArrays_() {
|
||||||
# DESC: Return items that exist in ARRAY1 that are do not exist in ARRAY2
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Array 1 in format ${ARRAY[*]}
|
# Merges two arrays together
|
||||||
# $2 (Required) - Array 2 in format ${ARRAY[*]}
|
# ARGS:
|
||||||
# OUTS: Prints unique terms
|
# $1 (Required) - Array 1
|
||||||
# USAGE: _setdiff_ "${array1[*]}" "${array2[*]}"
|
# $2 (Required) - Array 2
|
||||||
# NOTE: http://stackoverflow.com/a/1617303/142339
|
# OUTS:
|
||||||
|
# stdout: Prints result
|
||||||
|
# USAGE:
|
||||||
|
# newarray=($(_mergeArrays_ "array1[@]" "array2[@]"))
|
||||||
|
# NOTE:
|
||||||
|
# Note that the arrays must be passed in as strings
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
[[ $# -lt 2 ]] && fatal 'Missing required argument to _setdiff_()!'
|
[[ $# -ne 2 ]] && fatal 'Missing required argument to _mergeArrays_'
|
||||||
|
declare -a _arr1=("${!1}")
|
||||||
local debug skip a b
|
declare -a _arr2=("${!2}")
|
||||||
if [[ $1 == 1 ]]; then
|
declare _outputArray=("${_arr1[@]}" "${_arr2[@]}")
|
||||||
debug=1
|
printf "%s\n" "${_outputArray[@]}"
|
||||||
shift
|
|
||||||
fi
|
|
||||||
if [[ "$1" ]]; then
|
|
||||||
local setdiffA setdiffB setdiffC
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
setdiffA=($1)
|
|
||||||
# shellcheck disable=SC2206
|
|
||||||
setdiffB=($2)
|
|
||||||
fi
|
|
||||||
setdiffC=()
|
|
||||||
for a in "${setdiffA[@]}"; do
|
|
||||||
skip=
|
|
||||||
for b in "${setdiffB[@]}"; do
|
|
||||||
[[ $a == "$b" ]] && skip=1 && break
|
|
||||||
done
|
|
||||||
[[ "$skip" ]] || setdiffC=("${setdiffC[@]}" "$a")
|
|
||||||
done
|
|
||||||
[[ "$debug" ]] && for a in setdiffA setdiffB setdiffC; do
|
|
||||||
#shellcheck disable=SC1087
|
|
||||||
echo "$a ($(eval echo "\${#$a[*]}")) $(eval echo "\${$a[*]}")" 1>&2
|
|
||||||
done
|
|
||||||
[[ "$1" ]] && echo "${setdiffC[@]}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_removeDupes_() {
|
_reverseSortArray_() {
|
||||||
# DESC: Removes duplicate array elements.
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Input array
|
# Sorts an array from lowest to highest (z-a9-0)
|
||||||
# OUTS: Prints de-duped elements to standard out
|
# ARGS:
|
||||||
# USAGE: _removeDups_ "${array[@]}"
|
# $1 (Required) - Input array
|
||||||
# NOTE: List order may not stay the same.
|
# OUTS:
|
||||||
# https://github.com/dylanaraps/pure-bash-bible
|
# stdout: Prints result
|
||||||
declare -A tmp_array
|
# USAGE:
|
||||||
|
# _reverseSortArray_ "${array[@]}"
|
||||||
|
# NOTE:
|
||||||
|
# input=("c" "b" "4" "1" "2" "3" "a")
|
||||||
|
# _reverseSortArray_ "${input[@]}"
|
||||||
|
# c b a 4 3 2 1
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
for i in "$@"; do
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
[[ $i ]] && IFS=" " tmp_array["${i:- }"]=1
|
declare -a _array=("$@")
|
||||||
done
|
declare -a _sortedArray
|
||||||
|
mapfile -t _sortedArray < <(printf '%s\n' "${_array[@]}" | sort -r)
|
||||||
printf '%s\n' "${!tmp_array[@]}"
|
printf "%s\n" "${_sortedArray[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
_randomArrayElement_() {
|
_randomArrayElement_() {
|
||||||
# DESC: Selects a random item from an array
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Input array
|
# Selects a random item from an array
|
||||||
# OUTS: Prints result
|
# ARGS:
|
||||||
# USAGE: _randomArrayElement_ "${array[@]}"
|
# $1 (Required) - Input array
|
||||||
# NOTE: https://github.com/dylanaraps/pure-bash-bible
|
# OUTS:
|
||||||
# Usage: random_array_element "array"
|
# stdout: Prints one random element
|
||||||
local arr=("$@")
|
# USAGE:
|
||||||
printf '%s\n' "${arr[RANDOM % $#]}"
|
# _randomArrayElement_ "${array[@]}"
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/dylanaraps/pure-bash-bible
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
declare -a _array
|
||||||
|
local _array=("$@")
|
||||||
|
printf '%s\n' "${_array[RANDOM % $#]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_setDiff_() {
|
||||||
|
# DESC:
|
||||||
|
# Return items that exist in ARRAY1 that are do not exist in ARRAY2
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Array 1 (in format ARRAY[@])
|
||||||
|
# $2 (Required) - Array 2 (in format ARRAY[@])
|
||||||
|
# OUTS:
|
||||||
|
# 0 if unique elements found
|
||||||
|
# 1 if arrays are the same
|
||||||
|
# stdout: Prints unique elements
|
||||||
|
# USAGE:
|
||||||
|
# _setDiff_ "array1[@]" "array2[@]"
|
||||||
|
# mapfile -t NEW_ARRAY < <(_setDiff_ "array1[@]" "array2[@]")
|
||||||
|
# NOTE:
|
||||||
|
# Note that the arrays must be passed in as strings
|
||||||
|
# CREDIT:
|
||||||
|
# http://stackoverflow.com/a/1617303/142339
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _skip
|
||||||
|
local _a
|
||||||
|
local _b
|
||||||
|
declare -a _setdiffA=("${!1}")
|
||||||
|
declare -a _setdiffB=("${!2}")
|
||||||
|
declare -a _setdiffC=()
|
||||||
|
|
||||||
|
for _a in "${_setdiffA[@]}"; do
|
||||||
|
_skip=
|
||||||
|
for _b in "${_setdiffB[@]}"; do
|
||||||
|
if [[ ${_a} == "${_b}" ]]; then
|
||||||
|
_skip=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[[ "${_skip}" ]] || _setdiffC=("${_setdiffC[@]}" "${_a}")
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#_setdiffC[@]} == 0 ]]; then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
printf "%s\n" "${_setdiffC[@]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_sortArray_() {
|
||||||
|
# DESC:
|
||||||
|
# Sorts an array from lowest to highest (0-9 a-z)
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Input array
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints result
|
||||||
|
# USAGE:
|
||||||
|
# _sortArray_ "${array[@]}"
|
||||||
|
# NOTE:
|
||||||
|
# input=("c" "b" "4" "1" "2" "3" "a")
|
||||||
|
# _sortArray_ "${input[@]}"
|
||||||
|
# 1 2 3 4 a b c
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
declare -a _array=("$@")
|
||||||
|
declare -a _sortedArray
|
||||||
|
mapfile -t _sortedArray < <(printf '%s\n' "${_array[@]}" | sort)
|
||||||
|
printf "%s\n" "${_sortedArray[@]}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,373 +0,0 @@
|
|||||||
_execute_() {
|
|
||||||
# DESC: Executes commands with safety and logging options
|
|
||||||
# ARGS: $1 (Required) - The command to be executed. Quotation marks MUST be escaped.
|
|
||||||
# $2 (Optional) - String to display after command is executed
|
|
||||||
# OPTS: -v Always print debug output from the execute function
|
|
||||||
# -n Use NOTICE level alerting (default is INFO)
|
|
||||||
# -p Pass a failed command with 'return 0'. This effectively bypasses set -e.
|
|
||||||
# -e Bypass _alert_ functions and use 'echo RESULT'
|
|
||||||
# -s Use '_alert_ success' for successful output. (default is 'info')
|
|
||||||
# -q Do not print output (QUIET mode)
|
|
||||||
# OUTS: None
|
|
||||||
# USE : _execute_ "cp -R \"~/dir/somefile.txt\" \"someNewFile.txt\"" "Optional message"
|
|
||||||
# _execute_ -sv "mkdir \"some/dir\""
|
|
||||||
# NOTE:
|
|
||||||
# If $DRYRUN=true no commands are executed
|
|
||||||
# If $VERBOSE=true the command's native output is printed to
|
|
||||||
# stderr and stdin. This can be forced with `_execute_ -v`
|
|
||||||
|
|
||||||
local LOCAL_VERBOSE=false
|
|
||||||
local PASS_FAILURES=false
|
|
||||||
local ECHO_RESULT=false
|
|
||||||
local SUCCESS_RESULT=false
|
|
||||||
local QUIET_RESULT=false
|
|
||||||
local NOTICE_RESULT=false
|
|
||||||
local opt
|
|
||||||
|
|
||||||
local OPTIND=1
|
|
||||||
while getopts ":vVpPeEsSqQnN" opt; do
|
|
||||||
case $opt in
|
|
||||||
v | V) LOCAL_VERBOSE=true ;;
|
|
||||||
p | P) PASS_FAILURES=true ;;
|
|
||||||
e | E) ECHO_RESULT=true ;;
|
|
||||||
s | S) SUCCESS_RESULT=true ;;
|
|
||||||
q | Q) QUIET_RESULT=true ;;
|
|
||||||
n | N) NOTICE_RESULT=true ;;
|
|
||||||
*)
|
|
||||||
{
|
|
||||||
error "Unrecognized option '$1' passed to _execute_. Exiting."
|
|
||||||
_safeExit_
|
|
||||||
}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
local CMD="${1:?_execute_ needs a command}"
|
|
||||||
local EXECUTE_MESSAGE="${2:-$1}"
|
|
||||||
|
|
||||||
local SAVE_VERBOSE=${VERBOSE}
|
|
||||||
if "${LOCAL_VERBOSE}"; then
|
|
||||||
VERBOSE=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if "${DRYRUN}"; then
|
|
||||||
if "${QUIET_RESULT}"; then
|
|
||||||
VERBOSE=$SAVE_VERBOSE
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if [ -n "${2:-}" ]; then
|
|
||||||
dryrun "${1} (${2})" "$(caller)"
|
|
||||||
else
|
|
||||||
dryrun "${1}" "$(caller)"
|
|
||||||
fi
|
|
||||||
elif ${VERBOSE}; then
|
|
||||||
if eval "${CMD}"; then
|
|
||||||
if "${QUIET_RESULT}"; then
|
|
||||||
VERBOSE=${SAVE_VERBOSE}
|
|
||||||
return 0
|
|
||||||
elif "${ECHO_RESULT}"; then
|
|
||||||
echo "${EXECUTE_MESSAGE}"
|
|
||||||
elif "${SUCCESS_RESULT}"; then
|
|
||||||
success "${EXECUTE_MESSAGE}"
|
|
||||||
elif "${NOTICE_RESULT}"; then
|
|
||||||
notice "${EXECUTE_MESSAGE}"
|
|
||||||
else
|
|
||||||
info "${EXECUTE_MESSAGE}"
|
|
||||||
fi
|
|
||||||
VERBOSE=${SAVE_VERBOSE}
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
if "${ECHO_RESULT}"; then
|
|
||||||
echo "warning: ${EXECUTE_MESSAGE}"
|
|
||||||
else
|
|
||||||
warning "${EXECUTE_MESSAGE}"
|
|
||||||
fi
|
|
||||||
VERBOSE=${SAVE_VERBOSE}
|
|
||||||
"${PASS_FAILURES}" && return 0 || return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if eval "${CMD}" &>/dev/null; then
|
|
||||||
if "${QUIET_RESULT}"; then
|
|
||||||
VERBOSE=${SAVE_VERBOSE}
|
|
||||||
return 0
|
|
||||||
elif "${ECHO_RESULT}"; then
|
|
||||||
echo "${EXECUTE_MESSAGE}"
|
|
||||||
elif "${SUCCESS_RESULT}"; then
|
|
||||||
success "${EXECUTE_MESSAGE}"
|
|
||||||
elif "${NOTICE_RESULT}"; then
|
|
||||||
notice "${EXECUTE_MESSAGE}"
|
|
||||||
else
|
|
||||||
info "${EXECUTE_MESSAGE}"
|
|
||||||
fi
|
|
||||||
VERBOSE=${SAVE_VERBOSE}
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
if "${ECHO_RESULT}"; then
|
|
||||||
echo "error: ${EXECUTE_MESSAGE}"
|
|
||||||
else
|
|
||||||
warning "${EXECUTE_MESSAGE}"
|
|
||||||
fi
|
|
||||||
VERBOSE=${SAVE_VERBOSE}
|
|
||||||
"${PASS_FAILURES}" && return 0 || return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_findBaseDir_() {
|
|
||||||
# DESC: Locates the real directory of the script being run. Similar to GNU readlink -n
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: Echo result to STDOUT
|
|
||||||
# USE : baseDir="$(_findBaseDir_)"
|
|
||||||
# cp "$(_findBaseDir_ "somefile.txt")" "other_file.txt"
|
|
||||||
|
|
||||||
local SOURCE
|
|
||||||
local DIR
|
|
||||||
|
|
||||||
# Is file sourced?
|
|
||||||
[[ $_ != "$0" ]] \
|
|
||||||
&& SOURCE="${BASH_SOURCE[1]}" \
|
|
||||||
|| SOURCE="${BASH_SOURCE[0]}"
|
|
||||||
|
|
||||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
|
||||||
DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
|
|
||||||
SOURCE="$(readlink "$SOURCE")"
|
|
||||||
[[ $SOURCE != /* ]] && SOURCE="${DIR}/${SOURCE}" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
|
||||||
done
|
|
||||||
echo "$(cd -P "$(dirname "${SOURCE}")" && pwd)"
|
|
||||||
}
|
|
||||||
|
|
||||||
_checkBinary_() {
|
|
||||||
# DESC: Check if a binary exists in the search PATH
|
|
||||||
# ARGS: $1 (Required) - Name of the binary to check for existence
|
|
||||||
# OUTS: true/false
|
|
||||||
# USAGE: (_checkBinary_ ffmpeg ) && [SUCCESS] || [FAILURE]
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
error 'Missing required argument to _checkBinary_()!'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! command -v "$1" >/dev/null 2>&1; then
|
|
||||||
debug "Did not find dependency: '$1'"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_haveFunction_() {
|
|
||||||
# DESC: Tests if a function exists.
|
|
||||||
# ARGS: $1 (Required) - Function name
|
|
||||||
# OUTS: true/false
|
|
||||||
local f
|
|
||||||
f="$1"
|
|
||||||
|
|
||||||
if declare -f "${f}" &>/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_pauseScript_() {
|
|
||||||
# DESC: Pause a script at any point and continue after user input
|
|
||||||
# ARGS: $1 (Optional) - String for customized message
|
|
||||||
# OUTS: None
|
|
||||||
|
|
||||||
local pauseMessage
|
|
||||||
pauseMessage="${1:-Paused}. Ready to continue?"
|
|
||||||
|
|
||||||
if _seekConfirmation_ "${pauseMessage}"; then
|
|
||||||
info "Continuing..."
|
|
||||||
else
|
|
||||||
notice "Exiting Script"
|
|
||||||
_safeExit_
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_progressBar_() {
|
|
||||||
# DESC: Prints a progress bar within a for/while loop
|
|
||||||
# ARGS: $1 (Required) - The total number of items counted
|
|
||||||
# $2 (Optional) - The optional title of the progress bar
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE:
|
|
||||||
# for number in $(seq 0 100); do
|
|
||||||
# sleep 1
|
|
||||||
# _progressBar_ "100" "Counting numbers"
|
|
||||||
# done
|
|
||||||
|
|
||||||
($QUIET) && return
|
|
||||||
($VERBOSE) && return
|
|
||||||
[ ! -t 1 ] && return # Do nothing if the output is not a terminal
|
|
||||||
[ $1 == 1 ] && return # Do nothing with a single element
|
|
||||||
|
|
||||||
local width bar_char perc num bar progressBarLine barTitle n
|
|
||||||
|
|
||||||
n="${1:?_progressBar_ needs input}"
|
|
||||||
((n = n - 1))
|
|
||||||
barTitle="${2:-Running Process}"
|
|
||||||
width=30
|
|
||||||
bar_char="#"
|
|
||||||
|
|
||||||
# Reset the count
|
|
||||||
[ -z "${progressBarProgress}" ] && progressBarProgress=0
|
|
||||||
tput civis # Hide the cursor
|
|
||||||
trap 'tput cnorm; exit 1' SIGINT
|
|
||||||
|
|
||||||
if [ ! "${progressBarProgress}" -eq $n ]; then
|
|
||||||
#echo "progressBarProgress: $progressBarProgress"
|
|
||||||
# Compute the percentage.
|
|
||||||
perc=$((progressBarProgress * 100 / $1))
|
|
||||||
# Compute the number of blocks to represent the percentage.
|
|
||||||
num=$((progressBarProgress * width / $1))
|
|
||||||
# Create the progress bar string.
|
|
||||||
bar=""
|
|
||||||
if [ ${num} -gt 0 ]; then
|
|
||||||
bar=$(printf "%0.s${bar_char}" $(seq 1 ${num}))
|
|
||||||
fi
|
|
||||||
# Print the progress bar.
|
|
||||||
progressBarLine=$(printf "%s [%-${width}s] (%d%%)" " ${barTitle}" "${bar}" "${perc}")
|
|
||||||
echo -ne "${progressBarLine}\r"
|
|
||||||
progressBarProgress=$((progressBarProgress + 1))
|
|
||||||
else
|
|
||||||
# Clear the progress bar when complete
|
|
||||||
# echo -ne "\033[0K\r"
|
|
||||||
tput el # Clear the line
|
|
||||||
|
|
||||||
unset progressBarProgress
|
|
||||||
fi
|
|
||||||
|
|
||||||
tput cnorm
|
|
||||||
}
|
|
||||||
|
|
||||||
_rootAvailable_() {
|
|
||||||
# DESC: Validate we have superuser access as root (via sudo if requested)
|
|
||||||
# ARGS: $1 (optional): Set to any value to not attempt root access via sudo
|
|
||||||
# OUTS: None
|
|
||||||
# NOTE: https://github.com/ralish/bash-script-template
|
|
||||||
|
|
||||||
local superuser
|
|
||||||
if [[ ${EUID} -eq 0 ]]; then
|
|
||||||
superuser=true
|
|
||||||
elif [[ -z ${1:-} ]]; then
|
|
||||||
if command -v sudo &>/dev/null; then
|
|
||||||
debug 'Sudo: Updating cached credentials ...'
|
|
||||||
if ! sudo -v; then
|
|
||||||
warning "Sudo: Couldn't acquire credentials ..."
|
|
||||||
else
|
|
||||||
local test_euid
|
|
||||||
test_euid="$(sudo -H -- "$BASH" -c 'printf "%s" "$EUID"')"
|
|
||||||
if [[ ${test_euid} -eq 0 ]]; then
|
|
||||||
superuser=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z ${superuser:-} ]]; then
|
|
||||||
debug 'Unable to acquire superuser credentials.'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
debug 'Successfully acquired superuser credentials.'
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_runAsRoot_() {
|
|
||||||
# DESC: Run the requested command as root (via sudo if requested)
|
|
||||||
# ARGS: $1 (optional): Set to zero to not attempt execution via sudo
|
|
||||||
# $@ (required): Passed through for execution as root user
|
|
||||||
# OUTS: None
|
|
||||||
# NOTE: https://github.com/ralish/bash-script-template
|
|
||||||
|
|
||||||
if [[ $# -eq 0 ]]; then
|
|
||||||
fatal 'Missing required argument to _runAsRoot_()!'
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${1:-} =~ ^0$ ]]; then
|
|
||||||
local skip_sudo=true
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${EUID} -eq 0 ]]; then
|
|
||||||
"$@"
|
|
||||||
elif [[ -z ${skip_sudo:-} ]]; then
|
|
||||||
sudo -H -- "$@"
|
|
||||||
else
|
|
||||||
fatal "Unable to run requested command as root: $*"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_seekConfirmation_() {
|
|
||||||
# DESC: Seek user input for yes/no question
|
|
||||||
# ARGS: $1 (Optional) - Question being asked
|
|
||||||
# OUTS: true/false
|
|
||||||
# USAGE: _seekConfirmation_ "Do something?" && echo "okay" || echo "not okay"
|
|
||||||
# OR
|
|
||||||
# if _seekConfirmation_ "Answer this question"; then
|
|
||||||
# something
|
|
||||||
# fi
|
|
||||||
|
|
||||||
local yn
|
|
||||||
input "${1:-}"
|
|
||||||
if "${FORCE}"; then
|
|
||||||
debug "Forcing confirmation with '--force' flag set"
|
|
||||||
echo -e ""
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
while true; do
|
|
||||||
read -r -p " (y/n) " yn
|
|
||||||
case $yn in
|
|
||||||
[Yy]*) return 0 ;;
|
|
||||||
[Nn]*) return 1 ;;
|
|
||||||
*) input "Please answer yes or no." ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_setPATH_() {
|
|
||||||
# DESC: Add directories to $PATH so script can find executables
|
|
||||||
# ARGS: $@ - One or more paths
|
|
||||||
# OUTS: $PATH
|
|
||||||
# USAGE: _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)"
|
|
||||||
local NEWPATH NEWPATHS USERPATH
|
|
||||||
|
|
||||||
for USERPATH in "$@"; do
|
|
||||||
NEWPATHS+=("$USERPATH")
|
|
||||||
done
|
|
||||||
|
|
||||||
for NEWPATH in "${NEWPATHS[@]}"; do
|
|
||||||
if [ -d "${NEWPATH}" ]; then
|
|
||||||
if ! echo "$PATH" | grep -Eq "(^|:)${NEWPATH}($|:)"; then
|
|
||||||
PATH="${NEWPATH}:${PATH}"
|
|
||||||
debug "Added '${NEWPATH}' to PATH"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
_safeExit_() {
|
|
||||||
# DESC: Cleanup and exit from a script
|
|
||||||
# ARGS: $1 (optional) - Exit code (defaults to 0)
|
|
||||||
# OUTS: None
|
|
||||||
|
|
||||||
if [[ -d ${SCRIPT_LOCK:-} ]]; then
|
|
||||||
if command rm -rf "${SCRIPT_LOCK}"; then
|
|
||||||
debug "Removing script lock"
|
|
||||||
else
|
|
||||||
warning "Script lock could not be removed. Try manually deleting ${tan}'${LOCK_DIR}'${red}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
|
|
||||||
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
|
||||||
command rm -r "${TMP_DIR}"
|
|
||||||
else
|
|
||||||
command rm -r "${TMP_DIR}"
|
|
||||||
debug "Removing temp directory"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
trap - INT TERM EXIT
|
|
||||||
exit ${1:-0}
|
|
||||||
}
|
|
||||||
352
utilities/checks.bash
Normal file
352
utilities/checks.bash
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
# Functions for validating common use-cases
|
||||||
|
|
||||||
|
_binaryExists_() {
|
||||||
|
# DESC:
|
||||||
|
# Check if a binary exists in the search PATH
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Name of the binary to check for existence
|
||||||
|
# OUTS:
|
||||||
|
# 0 if true
|
||||||
|
# 1 if false
|
||||||
|
# USAGE:
|
||||||
|
# (_binaryExists_ ffmpeg ) && [SUCCESS] || [FAILURE]
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
debug "Did not find dependency: '${1}'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_functionExists_() {
|
||||||
|
# DESC:
|
||||||
|
# Tests if a function exists in the current scope
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Function name
|
||||||
|
# OUTS:
|
||||||
|
# 0 if function exists
|
||||||
|
# 1 if function does not exist
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _testFunction
|
||||||
|
_testFunction="${1}"
|
||||||
|
|
||||||
|
if declare -f "${_testFunction}" &>/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_isAlpha_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate that a given input is entirely alphabetic characters
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Input is only alphabetic characters
|
||||||
|
# 1 - Input contains non-alphabetic characters
|
||||||
|
# USAGE:
|
||||||
|
# _isAlpha_ "${var}"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _re='^[[:alpha:]]+$'
|
||||||
|
if [[ ${1} =~ ${_re} ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isAlphaNum_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate that a given input is entirely alpha-numeric characters
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Input is only alpha-numeric characters
|
||||||
|
# 1 - Input contains alpha-numeric characters
|
||||||
|
# USAGE:
|
||||||
|
# _isAlphaNum_ "${var}"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _re='^[[:alnum:]]+$'
|
||||||
|
if [[ ${1} =~ ${_re} ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isAlphaDash_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate that a given input contains only alpha-numeric characters, as well as dashes and underscores.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Input is only alpha-numeric or dash or underscore characters
|
||||||
|
# 1 - Input is not only alpha-numeric or dash or underscore characters
|
||||||
|
# USAGE:
|
||||||
|
# _isAlphaDash_ "${var}"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _re='^[[:alnum:]_-]+$'
|
||||||
|
if [[ ${1} =~ ${_re} ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isEmail_() {
|
||||||
|
# DESC:
|
||||||
|
# Validates that input is a valid email address
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Is valid email
|
||||||
|
# 1 - Is not valid email
|
||||||
|
# USAGE:
|
||||||
|
# _isEmail_ "somename+test@gmail.com"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _emailRegex
|
||||||
|
_emailRegex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$"
|
||||||
|
[[ ${1} =~ ${_emailRegex} ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInternetAvailable_() {
|
||||||
|
# DESC:
|
||||||
|
# Check if internet connection is available
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success: Internet connection is available
|
||||||
|
# 1 - Failure: Internet connection is not available
|
||||||
|
# stdout:
|
||||||
|
# USAGE:
|
||||||
|
# _isInternetAvailable_
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
local _checkInternet
|
||||||
|
if [[ -t 1 || -z ${TERM} ]]; then
|
||||||
|
_checkInternet="$(sh -ic 'exec 3>&1 2>/dev/null; { curl --compressed -Is google.com 1>&3; kill 0; } | { sleep 10; kill 0; }' || :)"
|
||||||
|
else
|
||||||
|
_checkInternet="$(curl --compressed -Is google.com -m 10)"
|
||||||
|
fi
|
||||||
|
if [[ -z ${_checkInternet:-} ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_isIPv4_() {
|
||||||
|
# DESC:
|
||||||
|
# Validates that input is a valid IP version 4 address
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Is valid IPv4 address
|
||||||
|
# 1 - Is not valid IPv4 address
|
||||||
|
# USAGE:
|
||||||
|
# _isIPv4_ "192.168.1.1"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _ip="${1}"
|
||||||
|
local IFS=.
|
||||||
|
# shellcheck disable=SC2206
|
||||||
|
declare -a _a=(${_ip})
|
||||||
|
[[ ${_ip} =~ ^[0-9]+(\.[0-9]+){3}$ ]] || return 1
|
||||||
|
# Test values of quads
|
||||||
|
local _quad
|
||||||
|
for _quad in {0..3}; do
|
||||||
|
[[ ${_a[${_quad}]} -gt 255 ]] && return 1
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_isFile_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate that a given input points to a valid file
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Input is a valid file
|
||||||
|
# 1 - Input is not a valid file
|
||||||
|
# USAGE:
|
||||||
|
# _varIsFile_ "${var}"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
[[ -f ${1} ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isDir_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate that a given input points to a valid directory
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Input is a directory
|
||||||
|
# 1 - Input is not a directory
|
||||||
|
# USAGE:
|
||||||
|
# _varIsDir_ "${var}"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
[[ -d ${1} ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isNum_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate that a given input is entirely numeric characters
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Input is only numeric characters
|
||||||
|
# 1 - Input contains numeric characters
|
||||||
|
# USAGE:
|
||||||
|
# _isNum_ "${var}"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _re='^[[:digit:]]+$'
|
||||||
|
if [[ ${1} =~ ${_re} ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isTerminal_() {
|
||||||
|
# DESC:
|
||||||
|
# Check is script is run in an interactive terminal
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Script is run in a terminal
|
||||||
|
# 1 - Script is not run in a terminal
|
||||||
|
# USAGE:
|
||||||
|
# _isTerminal_
|
||||||
|
|
||||||
|
[[ -t 1 || -z ${TERM} ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_rootAvailable_() {
|
||||||
|
# DESC:
|
||||||
|
# Validate we have superuser access as root (via sudo if requested)
|
||||||
|
# ARGS:
|
||||||
|
# $1 (optional): Set to any value to not attempt root access via sudo
|
||||||
|
# OUTS:
|
||||||
|
# 0 if true
|
||||||
|
# 1 if false
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/ralish/bash-script-template
|
||||||
|
|
||||||
|
local _superuser
|
||||||
|
local _testEUID
|
||||||
|
if [[ ${EUID} -eq 0 ]]; then
|
||||||
|
_superuser=true
|
||||||
|
elif [[ -z ${1:-} ]]; then
|
||||||
|
if command -v sudo >/dev/null 2>&1; then
|
||||||
|
debug 'Sudo: Updating cached credentials ...'
|
||||||
|
if ! sudo -v; then
|
||||||
|
warning "Sudo: Couldn't acquire credentials ..."
|
||||||
|
else
|
||||||
|
_testEUID="$(sudo -H -- "$BASH" -c 'printf "%s" "$EUID"')"
|
||||||
|
if [[ ${_testEUID} -eq 0 ]]; then
|
||||||
|
_superuser=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z ${superuser:-} ]]; then
|
||||||
|
debug 'Unable to acquire superuser credentials.'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
debug 'Successfully acquired superuser credentials.'
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_varIsTrue_() {
|
||||||
|
# DESC:
|
||||||
|
# Check if a given variable is true
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Variable to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Variable is true
|
||||||
|
# 1 - Variable is false
|
||||||
|
# USAGE
|
||||||
|
# _varIsTrue_ "${var}"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
[[ ${1} == true || ${1} -eq 0 ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_varIsFalse_() {
|
||||||
|
# DESC:
|
||||||
|
# Check if a given variable is false
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Variable to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Variable is false
|
||||||
|
# 1 - Variable is true
|
||||||
|
# USAGE
|
||||||
|
# _varIsFalse_ "${var}"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
[[ ${1} == false || ${1} -eq 1 ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_varIsEmpty_() {
|
||||||
|
# DESC:
|
||||||
|
# Check if given variable is empty or null.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Variable to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Variable is empty or null
|
||||||
|
# 1 - Variable is not empty or null
|
||||||
|
# USAGE
|
||||||
|
# _varIsEmpty_ "${var}"
|
||||||
|
|
||||||
|
[[ -z ${1} || ${1} == "null" ]] && return 0 || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_isIPv6_() {
|
||||||
|
# DESC:
|
||||||
|
# Validates that input is a valid IP version 46address
|
||||||
|
# ARGS:
|
||||||
|
# $1 (required): Input to check
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Is valid IPv6 address
|
||||||
|
# 1 - Is not valid IPv6 address
|
||||||
|
# USAGE:
|
||||||
|
# _isIPv6_ "2001:db8:85a3:8d3:1319:8a2e:370:7348"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _ip="${1}"
|
||||||
|
local _re="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|\
|
||||||
|
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|\
|
||||||
|
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|\
|
||||||
|
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|\
|
||||||
|
:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|\
|
||||||
|
::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|\
|
||||||
|
(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|\
|
||||||
|
(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
|
||||||
|
|
||||||
|
[[ ${_ip} =~ ${_re} ]] && return 0 || return 1
|
||||||
|
}
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
_makeCSV_() {
|
|
||||||
# Creates a new CSV file if one does not already exist
|
|
||||||
# Takes passed arguments and writes them as a header line to the CSV
|
|
||||||
# Usage '_makeCSV_ column1 column2 column3'
|
|
||||||
|
|
||||||
# Set the location and name of the CSV File
|
|
||||||
if [ -z "${csvLocation}" ]; then
|
|
||||||
csvLocation="${HOME}/Desktop"
|
|
||||||
fi
|
|
||||||
if [ -z "${csvName}" ]; then
|
|
||||||
csvName="$(LC_ALL=C date +%Y-%m-%d)-${FUNCNAME[1]}.csv"
|
|
||||||
fi
|
|
||||||
csvFile="${csvLocation}/${csvName}"
|
|
||||||
|
|
||||||
# Overwrite existing file? If not overwritten, new content is added
|
|
||||||
# to the bottom of the existing file
|
|
||||||
if [ -f "${csvFile}" ]; then
|
|
||||||
if _seekConfirmation_ "${csvFile} already exists. Overwrite?"; then
|
|
||||||
rm "${csvFile}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
_writeCSV_ "$@"
|
|
||||||
}
|
|
||||||
|
|
||||||
_writeCSV_() {
|
|
||||||
# Takes passed arguments and writes them as a comma separated line
|
|
||||||
# Usage '_writeCSV_ column1 column2 column3'
|
|
||||||
|
|
||||||
local csvInput=("$@")
|
|
||||||
saveIFS=$IFS
|
|
||||||
IFS=','
|
|
||||||
echo "${csvInput[*]}" >>"${csvFile}"
|
|
||||||
IFS=${saveIFS}
|
|
||||||
}
|
|
||||||
@@ -1,73 +1,216 @@
|
|||||||
|
# Functions to help work with dates and time
|
||||||
|
|
||||||
|
_convertToUnixTimestamp_() {
|
||||||
|
# DESC:
|
||||||
|
# Convert date string to unix timestamp
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Date to be converted
|
||||||
|
# OUTS:
|
||||||
|
# 0 If successful
|
||||||
|
# 1 If failed to convert
|
||||||
|
# stdout: timestamp for specified date/time
|
||||||
|
# USAGE:
|
||||||
|
# printf "%s\n" "$(_convertToUnixTimestamp_ "Jan 10, 2019")"
|
||||||
|
# NOTES:
|
||||||
|
#
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _date
|
||||||
|
_date=$(date -d "${1}" +"%s") || return 1
|
||||||
|
printf "%s\n" "${_date}"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_countdown_() {
|
||||||
|
# DESC:
|
||||||
|
# Sleep for a specified amount of time
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Optional) - Total seconds to sleep for(Default is 10)
|
||||||
|
# $2 (Optional) - Increment to count down
|
||||||
|
# $3 (Optional) - Message to print at each increment (default is ...)
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints the message at each increment
|
||||||
|
# USAGE:
|
||||||
|
# _countdown_ 10 1 "Waiting for cache to invalidate"
|
||||||
|
|
||||||
|
local i ii t
|
||||||
|
local _n=${1:-10}
|
||||||
|
local _sleepTime=${2:-1}
|
||||||
|
local _message="${3:-...}"
|
||||||
|
((t = _n + 1))
|
||||||
|
|
||||||
|
for ((i = 1; i <= _n; i++)); do
|
||||||
|
((ii = t - i))
|
||||||
|
if declare -f "info" &>/dev/null 2>&1; then
|
||||||
|
info "${_message} ${ii}"
|
||||||
|
else
|
||||||
|
echo "${_message} ${ii}"
|
||||||
|
fi
|
||||||
|
sleep ${_sleepTime}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_dateUnixTimestamp_() {
|
||||||
|
# DESC:
|
||||||
|
# Get the current time in unix timestamp
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints result ~ 1591554426
|
||||||
|
# 0 If successful
|
||||||
|
# 1 If failed to get timestamp
|
||||||
|
# USAGE:
|
||||||
|
# _dateUnixTimestamp_
|
||||||
|
|
||||||
|
local _now
|
||||||
|
_now="$(date --universal +%s)" || return 1
|
||||||
|
printf "%s\n" "${_now}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_formatDate_() {
|
||||||
|
# DESC:
|
||||||
|
# Reformats dates into user specified formats
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Date to be formatted
|
||||||
|
# $2 (Optional) - Format in any format accepted by bash's date command.
|
||||||
|
# Examples:
|
||||||
|
# %F - YYYY-MM-DD
|
||||||
|
# %D - MM/DD/YY
|
||||||
|
# %a - Name of weekday in short (like Sun, Mon, Tue, Wed, Thu, Fri, Sat)
|
||||||
|
# %A - Name of weekday in full (like Sunday, Monday, Tuesday)
|
||||||
|
# '+%m %d, %Y' - 12 27, 2019
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints result
|
||||||
|
# USAGE:
|
||||||
|
# _formatDate_ "Jan 10, 2019" "%D"
|
||||||
|
# NOTE:
|
||||||
|
# Defaults to YYYY-MM-DD or $(date +%F)
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _d="${1}"
|
||||||
|
local _format="${2:-%F}"
|
||||||
|
_format="${_format//+/}"
|
||||||
|
|
||||||
|
date -d "${_d}" "+${_format}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_fromSeconds_() {
|
||||||
|
# DESC:
|
||||||
|
# Convert seconds to HH:MM:SS
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Time in seconds
|
||||||
|
# OUTS:
|
||||||
|
# stdout: HH:MM:SS
|
||||||
|
# USAGE:
|
||||||
|
# _fromSeconds_ "SECONDS"
|
||||||
|
# EXAMPLE:
|
||||||
|
# To compute the time it takes a script to run:
|
||||||
|
# STARTTIME=$(date +"%s")
|
||||||
|
# ENDTIME=$(date +"%s")
|
||||||
|
# TOTALTIME=$(($ENDTIME-$STARTTIME)) # human readable time
|
||||||
|
# _fromSeconds_ "$TOTALTIME"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _h
|
||||||
|
local _m
|
||||||
|
local _s
|
||||||
|
|
||||||
|
((_h = ${1} / 3600))
|
||||||
|
((_m = (${1} % 3600) / 60))
|
||||||
|
((_s = ${1} % 60))
|
||||||
|
printf "%02d:%02d:%02d\n" ${_h} ${_m} ${_s}
|
||||||
|
}
|
||||||
|
|
||||||
_monthToNumber_() {
|
_monthToNumber_() {
|
||||||
# DESC: Convert a month name to a number
|
# DESC:
|
||||||
# ARGS: None
|
# Convert a month name to a number
|
||||||
# OUTS: Prints the number of the month to stdout
|
# ARGS:
|
||||||
# USAGE: _monthToNumber_ "January"
|
# $1 (Required) - Month name
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints the number of the month (1-12)
|
||||||
|
# USAGE:
|
||||||
|
# _monthToNumber_ "January"
|
||||||
|
|
||||||
local mon="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
case "$mon" in
|
|
||||||
|
local _mon="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
case "${_mon}" in
|
||||||
january | jan | ja) echo 1 ;;
|
january | jan | ja) echo 1 ;;
|
||||||
february | feb | fe) echo 2 ;;
|
february | feb | fe) echo 2 ;;
|
||||||
march | mar | ma) echo 3 ;;
|
march | mar | ma) echo 3 ;;
|
||||||
april | apr | ap) echo 4 ;;
|
april | apr | ap) echo 4 ;;
|
||||||
may) echo 5 ;;
|
may) echo 5 ;;
|
||||||
june | jun | ju) echo 6 ;;
|
june | jun | ju) echo 6 ;;
|
||||||
july | jul) echo 7 ;;
|
july | jul) echo 7 ;;
|
||||||
august | aug | au) echo 8 ;;
|
august | aug | au) echo 8 ;;
|
||||||
september | sep | se) echo 9 ;;
|
september | sep | se) echo 9 ;;
|
||||||
october | oct) echo 10 ;;
|
october | oct | oc) echo 10 ;;
|
||||||
november | nov | no) echo 11 ;;
|
november | nov | no) echo 11 ;;
|
||||||
december | dec | de) echo 12 ;;
|
december | dec | de) echo 12 ;;
|
||||||
*)
|
*)
|
||||||
warning "month_monthToNumber_: Bad monthname: $1"
|
warning "_monthToNumber_: Bad month name: ${_mon}"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
_numberToMonth_() {
|
_numberToMonth_() {
|
||||||
# DESC: Convert a month number to its name
|
# DESC:
|
||||||
# ARGS: None
|
# Convert a month number to its name
|
||||||
# OUTS: Prints the name of the month to stdout
|
# ARGS:
|
||||||
# USAGE: _numberToMonth_ 1
|
# $1 (Required) - Month number (1-12)
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints the name of the month
|
||||||
|
# USAGE:
|
||||||
|
# _numberToMonth_ 11
|
||||||
|
|
||||||
local mon="$1"
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
case "$mon" in
|
|
||||||
|
local _mon="$1"
|
||||||
|
case "${_mon}" in
|
||||||
1 | 01) echo January ;;
|
1 | 01) echo January ;;
|
||||||
2 | 02) echo February ;;
|
2 | 02) echo February ;;
|
||||||
3 | 03) echo March ;;
|
3 | 03) echo March ;;
|
||||||
4 | 04) echo April ;;
|
4 | 04) echo April ;;
|
||||||
5 | 05) echo May ;;
|
5 | 05) echo May ;;
|
||||||
6 | 06) echo June ;;
|
6 | 06) echo June ;;
|
||||||
7 | 07) echo July ;;
|
7 | 07) echo July ;;
|
||||||
8 | 08) echo August ;;
|
8 | 08) echo August ;;
|
||||||
9 | 09) echo September ;;
|
9 | 09) echo September ;;
|
||||||
10) echo October ;;
|
10) echo October ;;
|
||||||
11) echo November ;;
|
11) echo November ;;
|
||||||
12) echo December ;;
|
12) echo December ;;
|
||||||
*)
|
*)
|
||||||
warning "_numberToMonth_: Bad month number: $1"
|
warning "_numberToMonth_: Bad month number: ${_mon}"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
_parseDate_() {
|
_parseDate_() {
|
||||||
# DESC: Takes a string as input and attempts to find a date within it
|
# DESC:
|
||||||
# to parse into component parts (day, month, year)
|
# Takes a string as input and attempts to find a date within it to parse
|
||||||
# ARGS: $1 (required) - A string
|
# into component parts (day, month, year)
|
||||||
# OUTS: Returns error if no date found
|
# ARGS:
|
||||||
# $_parseDate_found - The date found in the string
|
# $1 (required) - A string
|
||||||
# $_parseDate_year - The year
|
# OUTS:
|
||||||
# $_parseDate_month - The number month
|
# 0 if date is found
|
||||||
# $_parseDate_monthName - The name of the month
|
# 1 if date is NOT found
|
||||||
# $_parseDate_day - The day
|
# If a date was found, the following variables are set:
|
||||||
# $_parseDate_hour - The hour (if avail)
|
# $PARSE_DATE_FOUND - The date found in the string
|
||||||
# $_parseDate_minute - The minute (if avail)
|
# $PARSE_DATE_YEAR - The year
|
||||||
# USAGE: if _parseDate_ "[STRING]"; then ...
|
# $PARSE_DATE_MONTH - The number month
|
||||||
# NOTE: This function only recognizes dates from the year 2000 to 2029
|
# $PARSE_DATE_MONTH_NAME - The name of the month
|
||||||
# NOTE: Will recognize dates in the following formats separated by '-_ ./'
|
# $PARSE_DATE_DAY - The day
|
||||||
|
# $PARSE_DATE_HOUR - The hour (if avail)
|
||||||
|
# $PARSE_DATE_MINUTE - The minute (if avail)
|
||||||
|
# USAGE:
|
||||||
|
# if _parseDate_ "[STRING]"; then ...
|
||||||
|
# NOTE:
|
||||||
|
# - This function only recognizes dates from the year 2000 to 202
|
||||||
|
# - Will recognize dates in the following formats separated by '-_ ./'
|
||||||
# * YYYY-MM-DD * Month DD, YYYY * DD Month, YYYY
|
# * YYYY-MM-DD * Month DD, YYYY * DD Month, YYYY
|
||||||
# * Month, YYYY * Month, DD YY * MM-DD-YYYY
|
# * Month, YYYY * Month, DD YY * MM-DD-YYYY
|
||||||
# * MMDDYYYY * YYYYMMDD * DDMMYYYY
|
# * MMDDYYYY * YYYYMMDD * DDMMYYYY
|
||||||
@@ -77,124 +220,122 @@ _parseDate_() {
|
|||||||
# * MMDDYY * YYMMDD * mon-DD-YY
|
# * MMDDYY * YYMMDD * mon-DD-YY
|
||||||
# TODO: Simplify and reduce the number of regex checks
|
# TODO: Simplify and reduce the number of regex checks
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
[[ $# -eq 0 ]] && {
|
local _stringToTest="${1}"
|
||||||
error 'Missing required argument to _parseDate_()!'
|
local _pat
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local date="${1:-$(date +%F)}"
|
PARSE_DATE_FOUND="" PARSE_DATE_YEAR="" PARSE_DATE_MONTH="" PARSE_DATE_MONTH_NAME=""
|
||||||
_parseDate_found="" _parseDate_year="" _parseDate_month="" _parseDate_monthName=""
|
PARSE_DATE_DAY="" PARSE_DATE_HOUR="" PARSE_DATE_MINUTE=""
|
||||||
_parseDate_day="" _parseDate_hour="" _parseDate_minute=""
|
|
||||||
|
|
||||||
shopt -s nocasematch #Use case-insensitive regex
|
shopt -s nocasematch #Use case-insensitive regex
|
||||||
|
|
||||||
debug "_parseDate_() input ${tan}$date${purple}"
|
debug "_parseDate_() input ${tan}$date${purple}"
|
||||||
|
|
||||||
# YYYY MM DD or YYYY-MM-DD
|
# 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].*|$)"
|
_pat="(.*[^0-9]|^)((20[0-2][0-9])[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2}))([^0-9].*|$)"
|
||||||
if [[ ${date} =~ $pat ]]; then
|
if [[ ${_stringToTest} =~ ${_pat} ]]; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[3]}))
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[4]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[5]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[5]}))
|
||||||
debug "regex match: ${tan}YYYY-MM-DD${purple}"
|
debug "regex match: ${tan}YYYY-MM-DD${purple}"
|
||||||
|
|
||||||
# Month DD, YYYY
|
# 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
|
elif [[ ${_stringToTest} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec)[-\./_ ]+([0-9]{1,2})(nd|rd|th|st)?,?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
|
||||||
_parseDate_found="${BASH_REMATCH[1]:-}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[1]:-}"
|
||||||
_parseDate_month=$(_monthToNumber_ ${BASH_REMATCH[2]:-})
|
PARSE_DATE_MONTH=$(_monthToNumber_ ${BASH_REMATCH[2]:-})
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month:-}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH:-}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[3]:-}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]:-}))
|
||||||
_parseDate_year=$((10#${BASH_REMATCH[5]:-}))
|
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]:-}))
|
||||||
debug "regex match: ${tan}Month DD, YYYY${purple}"
|
debug "regex match: ${tan}Month DD, YYYY${purple}"
|
||||||
|
|
||||||
# Month DD, YY
|
# 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
|
elif [[ ${_stringToTest} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec)[-\./_ ]+([0-9]{1,2})(nd|rd|th|st)?,?[-\./_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
|
||||||
_parseDate_found="${BASH_REMATCH[1]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
|
||||||
_parseDate_month=$(_monthToNumber_ ${BASH_REMATCH[2]})
|
PARSE_DATE_MONTH=$(_monthToNumber_ ${BASH_REMATCH[2]})
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]}))
|
||||||
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
|
||||||
debug "regex match: ${tan}Month DD, YY${purple}"
|
debug "regex match: ${tan}Month DD, YY${purple}"
|
||||||
|
|
||||||
# DD Month YYYY
|
# 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
|
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{2})[-\./_ ]+(january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec),?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day=$((10#"${BASH_REMATCH[3]}"))
|
PARSE_DATE_DAY=$((10#"${BASH_REMATCH[3]}"))
|
||||||
_parseDate_month="$(_monthToNumber_ "${BASH_REMATCH[4]}")"
|
PARSE_DATE_MONTH="$(_monthToNumber_ "${BASH_REMATCH[4]}")"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year=$((10#"${BASH_REMATCH[5]}"))
|
PARSE_DATE_YEAR=$((10#"${BASH_REMATCH[5]}"))
|
||||||
debug "regex match: ${tan}DD Month, YYYY${purple}"
|
debug "regex match: ${tan}DD Month, YYYY${purple}"
|
||||||
|
|
||||||
# MM-DD-YYYY or DD-MM-YYYY
|
# MM-DD-YYYY or DD-MM-YYYY
|
||||||
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
|
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
|
||||||
|
|
||||||
if [[ $((10#${BASH_REMATCH[3]})) -lt 13 &&
|
if [[ $((10#${BASH_REMATCH[3]})) -lt 13 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -gt 12 &&
|
$((10#${BASH_REMATCH[4]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year=$((10#${BASH_REMATCH[5]}))
|
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]}))
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
|
||||||
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -gt 12 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[3]})) -lt 32 &&
|
$((10#${BASH_REMATCH[3]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year=$((10#${BASH_REMATCH[5]}))
|
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]}))
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[4]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]}))
|
||||||
debug "regex match: ${tan}DD-MM-YYYY${purple}"
|
debug "regex match: ${tan}DD-MM-YYYY${purple}"
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -lt 32 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year=$((10#${BASH_REMATCH[5]}))
|
PARSE_DATE_YEAR=$((10#${BASH_REMATCH[5]}))
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
|
||||||
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
||||||
else
|
else
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
|
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{1,2})[-\.\/_ ]+([0-9]{1,2})[-\.\/_ ]+([0-9]{2}))([^0-9].*|$) ]]; then
|
||||||
|
|
||||||
if [[ $((10#${BASH_REMATCH[3]})) -lt 13 &&
|
if [[ $((10#${BASH_REMATCH[3]})) -lt 13 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -gt 12 &&
|
$((10#${BASH_REMATCH[4]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
|
||||||
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -gt 12 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[3]})) -lt 32 &&
|
$((10#${BASH_REMATCH[3]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[4]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[3]}))
|
||||||
debug "regex match: ${tan}DD-MM-YYYY${purple}"
|
debug "regex match: ${tan}DD-MM-YYYY${purple}"
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -lt 32 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_year="20$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_YEAR="20$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_month=$((10#${BASH_REMATCH[3]}))
|
PARSE_DATE_MONTH=$((10#${BASH_REMATCH[3]}))
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_day=$((10#${BASH_REMATCH[4]}))
|
PARSE_DATE_DAY=$((10#${BASH_REMATCH[4]}))
|
||||||
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
debug "regex match: ${tan}MM-DD-YYYY${purple}"
|
||||||
else
|
else
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
@@ -202,124 +343,124 @@ _parseDate_() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Month, YYYY
|
# 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
|
elif [[ ${_stringToTest} =~ ((january|jan|ja|february|feb|fe|march|mar|ma|april|apr|ap|may|june|jun|july|jul|ju|august|aug|september|sep|october|oct|november|nov|december|dec),?[-\./_ ]+(20[0-2][0-9]))([^0-9].*|$) ]]; then
|
||||||
_parseDate_found="${BASH_REMATCH[1]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
|
||||||
_parseDate_day="1"
|
PARSE_DATE_DAY="1"
|
||||||
_parseDate_month="$(_monthToNumber_ "${BASH_REMATCH[2]}")"
|
PARSE_DATE_MONTH="$(_monthToNumber_ "${BASH_REMATCH[2]}")"
|
||||||
_parseDate_monthName="$(_numberToMonth_ $_parseDate_month)"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ $PARSE_DATE_MONTH)"
|
||||||
_parseDate_year="$((10#${BASH_REMATCH[3]}))"
|
PARSE_DATE_YEAR="$((10#${BASH_REMATCH[3]}))"
|
||||||
debug "regex match: ${tan}Month, YYYY${purple}"
|
debug "regex match: ${tan}Month, YYYY${purple}"
|
||||||
|
|
||||||
# YYYYMMDDHHMM
|
# 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
|
elif [[ ${_stringToTest} =~ (.*[^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]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[4]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[4]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="$((10#${BASH_REMATCH[3]}))"
|
PARSE_DATE_YEAR="$((10#${BASH_REMATCH[3]}))"
|
||||||
_parseDate_hour="$((10#${BASH_REMATCH[6]}))"
|
PARSE_DATE_HOUR="$((10#${BASH_REMATCH[6]}))"
|
||||||
_parseDate_minute="$((10#${BASH_REMATCH[7]}))"
|
PARSE_DATE_MINUTE="$((10#${BASH_REMATCH[7]}))"
|
||||||
debug "regex match: ${tan}YYYYMMDDHHMM${purple}"
|
debug "regex match: ${tan}YYYYMMDDHHMM${purple}"
|
||||||
|
|
||||||
# YYYYMMDDHH 1 2 3 4 5 6
|
# 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
|
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)((20[0-2][0-9])([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[4]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[4]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="$((10#${BASH_REMATCH[3]}))"
|
PARSE_DATE_YEAR="$((10#${BASH_REMATCH[3]}))"
|
||||||
_parseDate_hour="${BASH_REMATCH[6]}"
|
PARSE_DATE_HOUR="${BASH_REMATCH[6]}"
|
||||||
_parseDate_minute="00"
|
PARSE_DATE_MINUTE="00"
|
||||||
debug "regex match: ${tan}YYYYMMDDHHMM${purple}"
|
debug "regex match: ${tan}YYYYMMDDHHMM${purple}"
|
||||||
|
|
||||||
# MMDDYYYY or YYYYMMDD or DDMMYYYY
|
# MMDDYYYY or YYYYMMDD or DDMMYYYY
|
||||||
# 1 2 3 4 5 6
|
# 1 2 3 4 5 6
|
||||||
elif [[ ${date} =~ (.*[^0-9]|^)(([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
|
elif [[ ${_stringToTest} =~ (.*[^0-9]|^)(([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2}))([^0-9].*|$) ]]; then
|
||||||
|
|
||||||
# MMDDYYYY
|
# MMDDYYYY
|
||||||
if [[ $((10#${BASH_REMATCH[5]})) -eq 20 &&
|
if [[ $((10#${BASH_REMATCH[5]})) -eq 20 &&
|
||||||
$((10#${BASH_REMATCH[3]})) -lt 13 &&
|
$((10#${BASH_REMATCH[3]})) -lt 13 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 32 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[4]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[4]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[3]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[3]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
|
PARSE_DATE_YEAR="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
|
||||||
debug "regex match: ${tan}MMDDYYYY${purple}"
|
debug "regex match: ${tan}MMDDYYYY${purple}"
|
||||||
# DDMMYYYY
|
# DDMMYYYY
|
||||||
elif [[ $((10#${BASH_REMATCH[5]})) -eq 20 &&
|
elif [[ $((10#${BASH_REMATCH[5]})) -eq 20 &&
|
||||||
$((10#${BASH_REMATCH[3]})) -gt 12 &&
|
$((10#${BASH_REMATCH[3]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[3]})) -lt 32 &&
|
$((10#${BASH_REMATCH[3]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[4]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[3]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[3]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[4]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[4]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
|
PARSE_DATE_YEAR="${BASH_REMATCH[5]}${BASH_REMATCH[6]}"
|
||||||
debug "regex match: ${tan}DDMMYYYY${purple}"
|
debug "regex match: ${tan}DDMMYYYY${purple}"
|
||||||
# YYYYMMDD
|
# YYYYMMDD
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
|
||||||
$((10#${BASH_REMATCH[6]})) -gt 12 &&
|
$((10#${BASH_REMATCH[6]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[6]})) -lt 32 &&
|
$((10#${BASH_REMATCH[6]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[6]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[6]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
|
PARSE_DATE_YEAR="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
|
||||||
debug "regex match: ${tan}YYYYMMDD${purple}"
|
debug "regex match: ${tan}YYYYMMDD${purple}"
|
||||||
# YYYYDDMM
|
# YYYYDDMM
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
|
||||||
$((10#${BASH_REMATCH[5]})) -gt 12 &&
|
$((10#${BASH_REMATCH[5]})) -gt 12 &&
|
||||||
$((10#${BASH_REMATCH[5]})) -lt 32 &&
|
$((10#${BASH_REMATCH[5]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[6]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[6]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[6]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[6]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
|
PARSE_DATE_YEAR="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
|
||||||
debug "regex match: ${tan}YYYYMMDD${purple}"
|
debug "regex match: ${tan}YYYYMMDD${purple}"
|
||||||
# Assume YYYMMDD
|
# Assume YYYMMDD
|
||||||
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
|
elif [[ $((10#${BASH_REMATCH[3]})) -eq 20 &&
|
||||||
$((10#${BASH_REMATCH[6]})) -lt 32 &&
|
$((10#${BASH_REMATCH[6]})) -lt 32 &&
|
||||||
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
|
$((10#${BASH_REMATCH[5]})) -lt 13 ]] \
|
||||||
; then
|
; then
|
||||||
_parseDate_found="${BASH_REMATCH[2]}"
|
PARSE_DATE_FOUND="${BASH_REMATCH[2]}"
|
||||||
_parseDate_day="$((10#${BASH_REMATCH[6]}))"
|
PARSE_DATE_DAY="$((10#${BASH_REMATCH[6]}))"
|
||||||
_parseDate_month="$((10#${BASH_REMATCH[5]}))"
|
PARSE_DATE_MONTH="$((10#${BASH_REMATCH[5]}))"
|
||||||
_parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
_parseDate_year="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
|
PARSE_DATE_YEAR="${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
|
||||||
debug "regex match: ${tan}YYYYMMDD${purple}"
|
debug "regex match: ${tan}YYYYMMDD${purple}"
|
||||||
else
|
else
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# # MMDD or DDYY
|
# # MMDD or DDYY
|
||||||
# elif [[ "$date" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then
|
# elif [[ "${_stringToTest}" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then
|
||||||
# debug "regex match: ${tan}MMDD or DDMM${purple}"
|
# debug "regex match: ${tan}MMDD or DDMM${purple}"
|
||||||
# _parseDate_found="${BASH_REMATCH[1]}"
|
# PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
|
||||||
|
|
||||||
# # Figure out if days are months or vice versa
|
# # Figure out if days are months or vice versa
|
||||||
# if [[ $(( 10#${BASH_REMATCH[2]} )) -gt 12 \
|
# if [[ $(( 10#${BASH_REMATCH[2]} )) -gt 12 \
|
||||||
# && $(( 10#${BASH_REMATCH[2]} )) -lt 32 \
|
# && $(( 10#${BASH_REMATCH[2]} )) -lt 32 \
|
||||||
# && $(( 10#${BASH_REMATCH[3]} )) -lt 13 \
|
# && $(( 10#${BASH_REMATCH[3]} )) -lt 13 \
|
||||||
# ]]; then
|
# ]]; then
|
||||||
# _parseDate_day="$(( 10#${BASH_REMATCH[2]} ))"
|
# PARSE_DATE_DAY="$(( 10#${BASH_REMATCH[2]} ))"
|
||||||
# _parseDate_month="$(( 10#${BASH_REMATCH[3]} ))"
|
# PARSE_DATE_MONTH="$(( 10#${BASH_REMATCH[3]} ))"
|
||||||
# _parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
# PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
# _parseDate_year="$(date +%Y )"
|
# PARSE_DATE_YEAR="$(date +%Y )"
|
||||||
# elif [[ $(( 10#${BASH_REMATCH[2]} )) -lt 13 \
|
# elif [[ $(( 10#${BASH_REMATCH[2]} )) -lt 13 \
|
||||||
# && $(( 10#${BASH_REMATCH[3]} )) -lt 32 \
|
# && $(( 10#${BASH_REMATCH[3]} )) -lt 32 \
|
||||||
# ]]; then
|
# ]]; then
|
||||||
# _parseDate_day="$(( 10#${BASH_REMATCH[3]} ))"
|
# PARSE_DATE_DAY="$(( 10#${BASH_REMATCH[3]} ))"
|
||||||
# _parseDate_month="$(( 10#${BASH_REMATCH[2]} ))"
|
# PARSE_DATE_MONTH="$(( 10#${BASH_REMATCH[2]} ))"
|
||||||
# _parseDate_monthName="$(_numberToMonth_ "${_parseDate_month}")"
|
# PARSE_DATE_MONTH_NAME="$(_numberToMonth_ "${PARSE_DATE_MONTH}")"
|
||||||
# _parseDate_year="$(date +%Y )"
|
# PARSE_DATE_YEAR="$(date +%Y )"
|
||||||
# else
|
# else
|
||||||
# shopt -u nocasematch
|
# shopt -u nocasematch
|
||||||
# return 1
|
# return 1
|
||||||
@@ -327,69 +468,102 @@ _parseDate_() {
|
|||||||
else
|
else
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ -z ${_parseDate_year:-} ]] && {
|
[[ -z ${PARSE_DATE_YEAR:-} ]] && {
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
((_parseDate_month >= 1 && _parseDate_month <= 12)) || {
|
((PARSE_DATE_MONTH >= 1 && PARSE_DATE_MONTH <= 12)) || {
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
((_parseDate_day >= 1 && _parseDate_day <= 31)) || {
|
((PARSE_DATE_DAY >= 1 && PARSE_DATE_DAY <= 31)) || {
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
debug "${tan}\$_parseDate_found: ${_parseDate_found}${purple}"
|
debug "${tan}\$PARSE_DATE_FOUND: ${PARSE_DATE_FOUND}${purple}"
|
||||||
debug "${tan}\$_parseDate_year: ${_parseDate_year}${purple}"
|
debug "${tan}\$PARSE_DATE_YEAR: ${PARSE_DATE_YEAR}${purple}"
|
||||||
debug "${tan}\$_parseDate_month: ${_parseDate_month}${purple}"
|
debug "${tan}\$PARSE_DATE_MONTH: ${PARSE_DATE_MONTH}${purple}"
|
||||||
debug "${tan}\$_parseDate_monthName: ${_parseDate_monthName}${purple}"
|
debug "${tan}\$PARSE_DATE_MONTH_NAME: ${PARSE_DATE_MONTH_NAME}${purple}"
|
||||||
debug "${tan}\$_parseDate_day: ${_parseDate_day}${purple}"
|
debug "${tan}\$PARSE_DATE_DAY: ${PARSE_DATE_DAY}${purple}"
|
||||||
[[ -z ${_parseDate_hour:-} ]] || debug "${tan}\$_parseDate_hour: ${_parseDate_hour}${purple}"
|
[[ -z ${PARSE_DATE_HOUR:-} ]] || debug "${tan}\$PARSE_DATE_HOUR: ${PARSE_DATE_HOUR}${purple}"
|
||||||
[[ -z ${_parseDate_minute:-} ]] || debug "${tan}\$_parseDate_minute: ${_parseDate_minute}${purple}"
|
[[ -z ${PARSE_DATE_MINUTE:-} ]] || debug "${tan}\$PARSE_DATE_MINUTE: ${PARSE_DATE_MINUTE}${purple}"
|
||||||
|
|
||||||
shopt -u nocasematch
|
shopt -u nocasematch
|
||||||
|
|
||||||
# Output results for BATS tests
|
# Output results for BATS tests
|
||||||
if [ "${automated_test_in_progress:-}" ]; then
|
if [ "${automated_test_in_progress:-}" ]; then
|
||||||
echo "_parseDate_found: ${_parseDate_found}"
|
echo "PARSE_DATE_FOUND: ${PARSE_DATE_FOUND}"
|
||||||
echo "_parseDate_year: ${_parseDate_year}"
|
echo "PARSE_DATE_YEAR: ${PARSE_DATE_YEAR}"
|
||||||
echo "_parseDate_month: ${_parseDate_month}"
|
echo "PARSE_DATE_MONTH: ${PARSE_DATE_MONTH}"
|
||||||
echo "_parseDate_monthName: ${_parseDate_monthName}"
|
echo "PARSE_DATE_MONTH_NAME: ${PARSE_DATE_MONTH_NAME}"
|
||||||
echo "_parseDate_day: ${_parseDate_day}"
|
echo "PARSE_DATE_DAY: ${PARSE_DATE_DAY}"
|
||||||
echo "_parseDate_hour: ${_parseDate_hour}"
|
echo "PARSE_DATE_HOUR: ${PARSE_DATE_HOUR}"
|
||||||
echo "_parseDate_minute: ${_parseDate_minute}"
|
echo "PARSE_DATE_MINUTE: ${PARSE_DATE_MINUTE}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_formatDate_() {
|
_readableUnixTimestamp_() {
|
||||||
# DESC: Reformats dates into user specified formats
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Date to be formatted
|
# Format unix timestamp to human readable format. If format string is not specified then
|
||||||
# $2 (Optional) - Format in any format accepted by bash's date command. Examples listed below.
|
# default to "yyyy-mm-dd hh:mm:ss"
|
||||||
# %F - YYYY-MM-DD
|
# ARGS:
|
||||||
# %D - MM/DD/YY
|
# $1 (Required) - Unix timestamp to be formatted
|
||||||
# %a - Name of weekday in short (like Sun, Mon, Tue, Wed, Thu, Fri, Sat)
|
# $2 (Optional) - Format string
|
||||||
# %A - Name of weekday in full (like Sunday, Monday, Tuesday)
|
# OUTS:
|
||||||
# '+%m %d, %Y' - 12 27, 2019
|
# 0 If successful
|
||||||
# OUTS: Echo result to STDOUT
|
# 1 If failed to convert
|
||||||
# USAGE: _formatDate_ "Jan 10, 2019" "%D"
|
# stdout: Human readable format of unix timestamp
|
||||||
# NOTE: Defaults to YYYY-MM-DD or $(date +%F)
|
# USAGE:
|
||||||
|
# _readableUnixTimestamp_ "1591554426"
|
||||||
|
# _readableUnixTimestamp_ "1591554426" "%Y-%m-%d"
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility/blob/master/src/date.sh
|
||||||
|
|
||||||
[[ $# -eq 0 ]] && {
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
error 'Missing required argument to _formatDate_()'
|
local _timestamp="${1}"
|
||||||
return 1
|
local _format="${2:-"%F %T"}"
|
||||||
}
|
local _out="$(date -d "@${_timestamp}" +"${_format}")" || return 1
|
||||||
|
printf "%s\n" "${_out}"
|
||||||
|
}
|
||||||
|
|
||||||
local d="${1}"
|
_toSeconds_() {
|
||||||
local format="${2:-%F}"
|
# DESC:
|
||||||
format="${format//+/}"
|
# Converts HH:MM:SS to seconds
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Time in HH:MM:SS
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Print seconds
|
||||||
|
# USAGE:
|
||||||
|
# _toSeconds_ "01:00:00"
|
||||||
|
# NOTE:
|
||||||
|
# Acceptable Input Formats
|
||||||
|
# 24 12 09
|
||||||
|
# 12,12,09
|
||||||
|
# 12;12;09
|
||||||
|
# 12:12:09
|
||||||
|
# 12-12-09
|
||||||
|
# 12H12M09S
|
||||||
|
# 12h12m09s
|
||||||
|
|
||||||
if command -v gdate >/dev/null 2>&1; then
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
gdate -d "${d}" "+${format}"
|
|
||||||
|
local _saveIFS
|
||||||
|
local _h
|
||||||
|
local _m
|
||||||
|
local _s
|
||||||
|
|
||||||
|
if [[ $1 =~ [0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2} ]]; then
|
||||||
|
_saveIFS="${IFS}"
|
||||||
|
IFS=":,;-_, HhMmSs" read -r h m s <<<"$1"
|
||||||
|
IFS="${_saveIFS}"
|
||||||
else
|
else
|
||||||
date -d "${d}" "+${format}"
|
_h="$1"
|
||||||
|
_m="$2"
|
||||||
|
_s="$3"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
printf "%s\n" "$((10#$_h * 3600 + 10#$_m * 60 + 10#$_s))"
|
||||||
}
|
}
|
||||||
|
|||||||
58
utilities/debug.bash
Normal file
58
utilities/debug.bash
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Functions to aid in debugging bash scripts
|
||||||
|
|
||||||
|
_pauseScript_() {
|
||||||
|
# DESC:
|
||||||
|
# Pause a script at any point and continue after user input
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Optional) - String for customized message
|
||||||
|
|
||||||
|
local _pauseMessage
|
||||||
|
_pauseMessage="${1:-Paused. Ready to continue?}"
|
||||||
|
|
||||||
|
if _seekConfirmation_ "${_pauseMessage}"; then
|
||||||
|
info "Continuing..."
|
||||||
|
else
|
||||||
|
notice "Exiting Script"
|
||||||
|
_safeExit_
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_printAnsi_() {
|
||||||
|
# DESC:
|
||||||
|
# Helps debug ansi escape sequence in text by displaying the escape codes
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) String input with ansi escape sequence.
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Ansi escape sequence printed in output as is.
|
||||||
|
# USAGE:
|
||||||
|
# _printAnsi_ "$(tput bold)$(tput setaf 9)Some Text"
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility/blob/master/src/debug.sh
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
#echo $(tr -dc '[:print:]'<<<$1)
|
||||||
|
printf "%s\n" "${1//$'\e'/\\e}"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_printArray_() {
|
||||||
|
# DESC:
|
||||||
|
# Prints the content of array as key value pairs for easier debugging
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String variable name of the array
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Formatted key value of array.one
|
||||||
|
# USAGE:
|
||||||
|
# testArray=("1" "2" "3" "4")
|
||||||
|
# _printArray_ "testArray"
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility/blob/master/src/debug.sh
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
declare -n _arr="${1}"
|
||||||
|
for _k in "${!_arr[@]}"; do
|
||||||
|
printf "%s = %s\n" "$_k" "${_arr[$_k]}"
|
||||||
|
done
|
||||||
|
}
|
||||||
1001
utilities/files.bash
1001
utilities/files.bash
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,18 @@
|
|||||||
# Functions for use on computers running MacOS
|
# Functions for use on computers running MacOS
|
||||||
|
|
||||||
_haveScriptableFinder_() {
|
_haveScriptableFinder_() {
|
||||||
# DESC: Determine whether we can script the Finder or not
|
# DESC:
|
||||||
# ARGS: None
|
# Determine whether we can script the Finder or not
|
||||||
# OUTS: true/false
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 if we can script the Finder
|
||||||
|
# 1 if not
|
||||||
|
|
||||||
local finder_pid
|
local _finder_pid
|
||||||
finder_pid="$(pgrep -f /System/Library/CoreServices/Finder.app | head -n 1)"
|
_finder_pid="$(pgrep -f /System/Library/CoreServices/Finder.app | head -n 1)"
|
||||||
|
|
||||||
if [[ (${finder_pid} -gt 1) && (${STY-} == "") ]]; then
|
if [[ (${_finder_pid} -gt 1) && (${STY-} == "") ]]; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
@@ -16,24 +20,56 @@ _haveScriptableFinder_() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_guiInput_() {
|
_guiInput_() {
|
||||||
# DESC: Ask for user input using a Mac dialog box
|
# DESC:
|
||||||
# ARGS: $1 (Optional) - Text in dialogue box (Default: Password)
|
# Ask for user input using a Mac dialog box
|
||||||
# OUTS: None
|
# ARGS:
|
||||||
# NOTE: https://github.com/herrbischoff/awesome-osx-command-line/blob/master/functions.md
|
# $1 (Optional) - Text in dialogue box (Default: Password)
|
||||||
|
# OUTS:
|
||||||
|
# MacOS dialog box output
|
||||||
|
# 1 if no output
|
||||||
|
# CREDIT
|
||||||
|
# https://github.com/herrbischoff/awesome-osx-command-line/blob/master/functions.md
|
||||||
if _haveScriptableFinder_; then
|
if _haveScriptableFinder_; then
|
||||||
guiPrompt="${1:-Password:}"
|
local _guiPrompt="${1:-Password:}"
|
||||||
guiInput=$(
|
local _guiInput=$(
|
||||||
osascript &>/dev/null <<EOF
|
osascript &>/dev/null <<GUI_INPUT_MESSAGE
|
||||||
tell application "System Events"
|
tell application "System Events"
|
||||||
activate
|
activate
|
||||||
text returned of (display dialog "${guiPrompt}" default answer "" with hidden answer)
|
text returned of (display dialog "${_guiPrompt}" default answer "" with hidden answer)
|
||||||
end tell
|
end tell
|
||||||
EOF
|
GUI_INPUT_MESSAGE
|
||||||
)
|
)
|
||||||
echo -n "${guiInput}"
|
echo -n "${_guiInput}"
|
||||||
else
|
else
|
||||||
error "No GUI input without macOS"
|
error "No GUI input without macOS"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_useGNUutils_() {
|
||||||
|
# DESC:
|
||||||
|
# Add GNU utilities to PATH to allow consistent use of sed/grep/tar/etc. on MacOS
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 if successful
|
||||||
|
# 1 if unsuccessful
|
||||||
|
# PATH: Adds GNU utilities to the path
|
||||||
|
# USAGE:
|
||||||
|
# # if ! _useGNUUtils_; then exit 1; fi
|
||||||
|
# NOTES:
|
||||||
|
# GNU utilities can be added to MacOS using Homebrew
|
||||||
|
|
||||||
|
[ ! "$(declare -f "_setPATH_")" ] && fatal "${FUNCNAME[0]} needs function _setPATH_"
|
||||||
|
|
||||||
|
if _setPATH_ \
|
||||||
|
"/usr/local/opt/gnu-tar/libexec/gnubin" \
|
||||||
|
"/usr/local/opt/coreutils/libexec/gnubin" \
|
||||||
|
"/usr/local/opt/gnu-sed/libexec/gnubin" \
|
||||||
|
"/usr/local/opt/grep/libexec/gnubin"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|||||||
482
utilities/misc.bash
Normal file
482
utilities/misc.bash
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
# Functions which provide base functionality for other scripts
|
||||||
|
|
||||||
|
_checkTerminalSize_() {
|
||||||
|
# DESC:
|
||||||
|
# Checks the size of the terminal window. Updates LINES/COLUMNS if necessary
|
||||||
|
# ARGS:
|
||||||
|
# NONE
|
||||||
|
# OUTS:
|
||||||
|
# NONE
|
||||||
|
# USAGE:
|
||||||
|
# _updateTerminalSize_
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
shopt -s checkwinsize && (: && :)
|
||||||
|
trap 'shopt -s checkwinsize; (:;:)' SIGWINCH
|
||||||
|
}
|
||||||
|
|
||||||
|
_detectOS_() {
|
||||||
|
# DESC:
|
||||||
|
# Identify the OS the script is run on
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Failed to detect OS
|
||||||
|
# stdout: One of 'mac', 'linux', 'windows'
|
||||||
|
# USAGE:
|
||||||
|
# _detectOS_
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
local _uname
|
||||||
|
local _os
|
||||||
|
if _uname=$(command -v uname); then
|
||||||
|
case $("${_uname}" | tr '[:upper:]' '[:lower:]') in
|
||||||
|
linux*)
|
||||||
|
_os="linux"
|
||||||
|
;;
|
||||||
|
darwin*)
|
||||||
|
_os="mac"
|
||||||
|
;;
|
||||||
|
msys* | cygwin* | mingw* | nt | win*)
|
||||||
|
# or possible 'bash on windows'
|
||||||
|
_os="windows"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf "%s" "${_os}"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_detectLinuxDistro_() {
|
||||||
|
# DESC:
|
||||||
|
# Detects the Linux distribution of the host the script is run on
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - If Linux distro is successfully detected
|
||||||
|
# 1 - If unable to detect OS distro or not on Linux
|
||||||
|
# stdout: Prints name of Linux distro in lower case (ex: 'raspbian' or 'debian')
|
||||||
|
# USAGE:
|
||||||
|
# _detectLinuxDistro_
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
local _distro
|
||||||
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. "/etc/os-release"
|
||||||
|
_distro="${NAME}"
|
||||||
|
elif type lsb_release >/dev/null 2>&1; then
|
||||||
|
# linuxbase.org
|
||||||
|
_distro=$(lsb_release -si)
|
||||||
|
elif [[ -f /etc/lsb-release ]]; then
|
||||||
|
# For some versions of Debian/Ubuntu without lsb_release command
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/lsb-release
|
||||||
|
_distro="${DISTRIB_ID}"
|
||||||
|
elif [[ -f /etc/debian_version ]]; then
|
||||||
|
# Older Debian/Ubuntu/etc.
|
||||||
|
_distro="debian"
|
||||||
|
elif [[ -f /etc/SuSe-release ]]; then
|
||||||
|
# Older SuSE/etc.
|
||||||
|
_distro="suse"
|
||||||
|
elif [[ -f /etc/redhat-release ]]; then
|
||||||
|
# Older Red Hat, CentOS, etc.
|
||||||
|
_distro="redhat"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf "%s" "${_distro}" | tr '[:upper:]' '[:lower:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
_detectMacOSVersion_() {
|
||||||
|
# DESC:
|
||||||
|
# Detects the host's version of MacOS
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Can not find macOS version number or not on a mac
|
||||||
|
# stdout: Prints the version number of macOS (ex: 11.6.1)
|
||||||
|
# USAGE:
|
||||||
|
# _detectMacOSVersion_
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
[ ! "$(declare -f "_detectOS_")" ] && fatal "${FUNCNAME[0]} needs function _detectOS_"
|
||||||
|
|
||||||
|
if [[ "$(_detectOS_)" == "mac" ]]; then
|
||||||
|
local _mac_version
|
||||||
|
_mac_version="$(sw_vers -productVersion)"
|
||||||
|
printf "%s" "${_mac_version}"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_detectLinuxDistro_() {
|
||||||
|
# DESC:
|
||||||
|
# Detects the Linux distribution of the host the script is run on
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - If Linux distro is successfully detected
|
||||||
|
# 1 - If unable to detect OS distro or not on Linux
|
||||||
|
# stdout: Prints name of Linux distro in lower case (ex: 'raspbian' or 'debian')
|
||||||
|
# USAGE:
|
||||||
|
# _detectLinuxDistro_
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
local _distro
|
||||||
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. "/etc/os-release"
|
||||||
|
_distro="${NAME}"
|
||||||
|
elif type lsb_release >/dev/null 2>&1; then
|
||||||
|
# linuxbase.org
|
||||||
|
_distro=$(lsb_release -si)
|
||||||
|
elif [[ -f /etc/lsb-release ]]; then
|
||||||
|
# For some versions of Debian/Ubuntu without lsb_release command
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
. /etc/lsb-release
|
||||||
|
_distro="${DISTRIB_ID}"
|
||||||
|
elif [[ -f /etc/debian_version ]]; then
|
||||||
|
# Older Debian/Ubuntu/etc.
|
||||||
|
_distro="debian"
|
||||||
|
elif [[ -f /etc/SuSe-release ]]; then
|
||||||
|
# Older SuSE/etc.
|
||||||
|
_distro="suse"
|
||||||
|
elif [[ -f /etc/redhat-release ]]; then
|
||||||
|
# Older Red Hat, CentOS, etc.
|
||||||
|
_distro="redhat"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
printf "%s" "${_distro}" | tr '[:upper:]' '[:lower:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
_execute_() {
|
||||||
|
# DESC:
|
||||||
|
# Executes commands while respecting global DRYRUN, VERBOSE, LOGGING, and QUIET flags
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - The command to be executed. Quotation marks MUST be escaped.
|
||||||
|
# $2 (Optional) - String to display after command is executed
|
||||||
|
# OPTS:
|
||||||
|
# -v Always print output from the execute function to STDOUT
|
||||||
|
# -n Use NOTICE level alerting (default is INFO)
|
||||||
|
# -p Pass a failed command with 'return 0'. This effectively bypasses set -e.
|
||||||
|
# -e Bypass _alert_ functions and use 'echo RESULT'
|
||||||
|
# -s Use '_alert_ success' for successful output. (default is 'info')
|
||||||
|
# -q Do not print output (QUIET mode)
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Configurable output
|
||||||
|
# USE :
|
||||||
|
# _execute_ "cp -R \"~/dir/somefile.txt\" \"someNewFile.txt\"" "Optional message"
|
||||||
|
# _execute_ -sv "mkdir \"some/dir\""
|
||||||
|
# NOTE:
|
||||||
|
# If $DRYRUN=true, no commands are executed and the command that would have been executed
|
||||||
|
# is printed to STDOUT using dryrun level alerting
|
||||||
|
# If $VERBOSE=true, the command's native output is printed to stdout. This can be forced
|
||||||
|
# with '_execute_ -v'
|
||||||
|
|
||||||
|
local _localVerbose=false
|
||||||
|
local _passFailures=false
|
||||||
|
local _echoResult=false
|
||||||
|
local _echoSuccessResult=false
|
||||||
|
local _quietMode=false
|
||||||
|
local _echoNoticeResult=false
|
||||||
|
local opt
|
||||||
|
|
||||||
|
local OPTIND=1
|
||||||
|
while getopts ":vVpPeEsSqQnN" opt; do
|
||||||
|
case $opt in
|
||||||
|
v | V) _localVerbose=true ;;
|
||||||
|
p | P) _passFailures=true ;;
|
||||||
|
e | E) _echoResult=true ;;
|
||||||
|
s | S) _echoSuccessResult=true ;;
|
||||||
|
q | Q) _quietMode=true ;;
|
||||||
|
n | N) _echoNoticeResult=true ;;
|
||||||
|
*)
|
||||||
|
{
|
||||||
|
error "Unrecognized option '$1' passed to _execute_. Exiting."
|
||||||
|
_safeExit_
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _command="${1}"
|
||||||
|
local _executeMessage="${2:-$1}"
|
||||||
|
|
||||||
|
local _saveVerbose=${VERBOSE}
|
||||||
|
if "${_localVerbose}"; then
|
||||||
|
VERBOSE=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if "${DRYRUN}"; then
|
||||||
|
if "${_quietMode}"; then
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ -n "${2:-}" ]; then
|
||||||
|
dryrun "${1} (${2})" "$(caller)"
|
||||||
|
else
|
||||||
|
dryrun "${1}" "$(caller)"
|
||||||
|
fi
|
||||||
|
elif ${VERBOSE}; then
|
||||||
|
if eval "${_command}"; then
|
||||||
|
if "${_quietMode}"; then
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
elif "${_echoResult}"; then
|
||||||
|
printf "%s\n" "${_executeMessage}"
|
||||||
|
elif "${_echoSuccessResult}"; then
|
||||||
|
success "${_executeMessage}"
|
||||||
|
elif "${_echoNoticeResult}"; then
|
||||||
|
notice "${_executeMessage}"
|
||||||
|
else
|
||||||
|
info "${_executeMessage}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if "${_quietMode}"; then
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
elif "${_echoResult}"; then
|
||||||
|
printf "%s\n" "warning: ${_executeMessage}"
|
||||||
|
else
|
||||||
|
warning "${_executeMessage}"
|
||||||
|
fi
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
"${_passFailures}" && return 0 || return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if eval "${_command}" >/dev/null 2>&1; then
|
||||||
|
if "${_quietMode}"; then
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
elif "${_echoResult}"; then
|
||||||
|
printf "%s\n" "${_executeMessage}"
|
||||||
|
elif "${_echoSuccessResult}"; then
|
||||||
|
success "${_executeMessage}"
|
||||||
|
elif "${_echoNoticeResult}"; then
|
||||||
|
notice "${_executeMessage}"
|
||||||
|
else
|
||||||
|
info "${_executeMessage}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if "${_quietMode}"; then
|
||||||
|
VERBOSE=$_saveVerbose
|
||||||
|
elif "${_echoResult}"; then
|
||||||
|
printf "%s\n" "error: ${_executeMessage}"
|
||||||
|
else
|
||||||
|
warning "${_executeMessage}"
|
||||||
|
fi
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
"${_passFailures}" && return 0 || return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
VERBOSE=${_saveVerbose}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_findBaseDir_() {
|
||||||
|
# DESC:
|
||||||
|
# Locates the real directory of the script being run. Similar to GNU readlink -n
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# stdout: prints result
|
||||||
|
# USAGE:
|
||||||
|
# baseDir="$(_findBaseDir_)"
|
||||||
|
# cp "$(_findBaseDir_ "somefile.txt")" "other_file.txt"
|
||||||
|
|
||||||
|
local _source
|
||||||
|
local _dir
|
||||||
|
|
||||||
|
# Is file sourced?
|
||||||
|
[[ $_ != "$0" ]] \
|
||||||
|
&& _source="${BASH_SOURCE[1]}" \
|
||||||
|
|| _source="${BASH_SOURCE[0]}"
|
||||||
|
|
||||||
|
while [ -h "${_source}" ]; do # Resolve $SOURCE until the file is no longer a symlink
|
||||||
|
_dir="$(cd -P "$(dirname "${_source}")" && pwd)"
|
||||||
|
_source="$(readlink "${_source}")"
|
||||||
|
[[ ${_source} != /* ]] && _source="${_dir}/${_source}" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||||
|
done
|
||||||
|
printf "%s/n" "$(cd -P "$(dirname "${_source}")" && pwd)"
|
||||||
|
}
|
||||||
|
|
||||||
|
_generateUUID_() {
|
||||||
|
# DESC:
|
||||||
|
# Generates a UUID
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Failure
|
||||||
|
# stdout: UUID
|
||||||
|
# USAGE:
|
||||||
|
# _generateUUID_
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility
|
||||||
|
|
||||||
|
local _c
|
||||||
|
local n
|
||||||
|
local _b
|
||||||
|
_c="89ab"
|
||||||
|
|
||||||
|
for ((n = 0; n < 16; ++n)); do
|
||||||
|
_b="$((RANDOM % 256))"
|
||||||
|
|
||||||
|
case "$n" in
|
||||||
|
6) printf '4%x' "$((_b % 16))" ;;
|
||||||
|
8) printf '%c%x' "${_c:$RANDOM%${#_c}:1}" "$((_b % 16))" ;;
|
||||||
|
|
||||||
|
3 | 5 | 7 | 9)
|
||||||
|
printf '%02x-' "${_b}"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
printf '%02x' "${_b}"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
printf '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
_makeProgressBar_() {
|
||||||
|
# DESC:
|
||||||
|
# Prints a progress bar within a for/while loop
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - The total number of items counted
|
||||||
|
# $2 (Optional) - The optional title of the progress bar
|
||||||
|
# OUTS: stdout: progress bar
|
||||||
|
# USAGE:
|
||||||
|
# for number in $(seq 0 100); do
|
||||||
|
# sleep 1
|
||||||
|
# _makeProgressBar_ "100" "Counting numbers"
|
||||||
|
# done
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && return # Do nothing if no arguments are passed
|
||||||
|
(${QUIET}) && return
|
||||||
|
(${VERBOSE}) && return
|
||||||
|
[ ! -t 1 ] && return # Do nothing if the output is not a terminal
|
||||||
|
[ ${1} == 1 ] && return # Do nothing with a single element
|
||||||
|
|
||||||
|
local n="${1}"
|
||||||
|
local _width=30
|
||||||
|
local _barCharacter="#"
|
||||||
|
local _percentage
|
||||||
|
local _num
|
||||||
|
local _bar
|
||||||
|
local _progressBarLine
|
||||||
|
local _barTitle="${2:-Running Process}"
|
||||||
|
local n
|
||||||
|
|
||||||
|
((n = n - 1))
|
||||||
|
|
||||||
|
# Reset the count
|
||||||
|
[ -z "${progressBarProgress:-}" ] && progressBarProgress=0
|
||||||
|
tput civis # Hide the cursor
|
||||||
|
trap 'tput cnorm; exit 1' SIGINT
|
||||||
|
|
||||||
|
if [ ! "${progressBarProgress}" -eq $n ]; then
|
||||||
|
#echo "progressBarProgress: $progressBarProgress"
|
||||||
|
# Compute the percentage.
|
||||||
|
_percentage=$((progressBarProgress * 100 / $1))
|
||||||
|
# Compute the number of blocks to represent the percentage.
|
||||||
|
_num=$((progressBarProgress * _width / $1))
|
||||||
|
# Create the progress bar string.
|
||||||
|
_bar=""
|
||||||
|
if [ ${_num} -gt 0 ]; then
|
||||||
|
_bar=$(printf "%0.s${_barCharacter}" $(seq 1 ${_num}))
|
||||||
|
fi
|
||||||
|
# Print the progress bar.
|
||||||
|
_progressBarLine=$(printf "%s [%-${_width}s] (%d%%)" " ${_barTitle}" "${_bar}" "${_percentage}")
|
||||||
|
printf "%s\r" "${_progressBarLine}"
|
||||||
|
# echo -ne "${_progressBarLine}\r"
|
||||||
|
progressBarProgress=$((progressBarProgress + 1))
|
||||||
|
else
|
||||||
|
# Clear the progress bar when complete
|
||||||
|
# echo -ne "\033[0K\r"
|
||||||
|
tput el # Clear the line
|
||||||
|
|
||||||
|
unset progressBarProgress
|
||||||
|
fi
|
||||||
|
|
||||||
|
tput cnorm
|
||||||
|
}
|
||||||
|
|
||||||
|
_runAsRoot_() {
|
||||||
|
# DESC:
|
||||||
|
# Run the requested command as root (via sudo if requested)
|
||||||
|
# ARGS:
|
||||||
|
# $1 (optional): Set to zero to not attempt execution via sudo
|
||||||
|
# $@ (required): Passed through for execution as root user
|
||||||
|
# OUTS:
|
||||||
|
# Runs the requested command as root
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/ralish/bash-script-template
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _skip_sudo=false
|
||||||
|
|
||||||
|
if [[ ${1} =~ ^0$ ]]; then
|
||||||
|
_skip_sudo=true
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${EUID} -eq 0 ]]; then
|
||||||
|
"$@"
|
||||||
|
elif [[ -z ${_skip_sudo} ]]; then
|
||||||
|
sudo -H -- "$@"
|
||||||
|
else
|
||||||
|
fatal "Unable to run requested command as root: $*"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_seekConfirmation_() {
|
||||||
|
# DESC:
|
||||||
|
# Seek user input for yes/no question
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Question being asked
|
||||||
|
# OUTS:
|
||||||
|
# 0 if answer is "yes"
|
||||||
|
# 1 if answer is "no"
|
||||||
|
# USAGE:
|
||||||
|
# _seekConfirmation_ "Do something?" && echo "okay" || echo "not okay"
|
||||||
|
# OR
|
||||||
|
# if _seekConfirmation_ "Answer this question"; then
|
||||||
|
# something
|
||||||
|
# fi
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _yesNo
|
||||||
|
input "${1}"
|
||||||
|
if "${FORCE}"; then
|
||||||
|
debug "Forcing confirmation with '--force' flag set"
|
||||||
|
echo -e ""
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
while true; do
|
||||||
|
read -r -p " (y/n) " _yesNo
|
||||||
|
case ${_yesNo} in
|
||||||
|
[Yy]*) return 0 ;;
|
||||||
|
[Nn]*) return 1 ;;
|
||||||
|
*) input "Please answer yes or no." ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
_fromSeconds_() {
|
|
||||||
# DESC: Convert seconds to HH:MM:SS
|
|
||||||
# ARGS: $1 (Required) - Time in seconds
|
|
||||||
# OUTS: Print HH:MM:SS to STDOUT
|
|
||||||
# USAGE: _convertSecs_ "SECONDS"
|
|
||||||
# To compute the time it takes a script to run:
|
|
||||||
# STARTTIME=$(date +"%s")
|
|
||||||
# ENDTIME=$(date +"%s")
|
|
||||||
# TOTALTIME=$(($ENDTIME-$STARTTIME)) # human readable time
|
|
||||||
# _convertSecs_ "$TOTALTIME"
|
|
||||||
|
|
||||||
((h = ${1} / 3600))
|
|
||||||
((m = (${1} % 3600) / 60))
|
|
||||||
((s = ${1} % 60))
|
|
||||||
printf "%02d:%02d:%02d\n" $h $m $s
|
|
||||||
}
|
|
||||||
|
|
||||||
_toSeconds_() {
|
|
||||||
# DESC: Converts HH:MM:SS to seconds
|
|
||||||
# ARGS: $1 (Required) - Time in HH:MM:SS
|
|
||||||
# OUTS: Print seconds to STDOUT
|
|
||||||
# USAGE: _toSeconds_ "01:00:00"
|
|
||||||
# NOTE: Acceptable Input Formats
|
|
||||||
# 24 12 09
|
|
||||||
# 12,12,09
|
|
||||||
# 12;12;09
|
|
||||||
# 12:12:09
|
|
||||||
# 12-12-09
|
|
||||||
# 12H12M09S
|
|
||||||
# 12h12m09s
|
|
||||||
|
|
||||||
local saveIFS
|
|
||||||
local h
|
|
||||||
local m
|
|
||||||
local s
|
|
||||||
|
|
||||||
if [[ $1 =~ [0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2}(:|,|-|_|,| |[hHmMsS])[0-9]{1,2} ]]; then
|
|
||||||
saveIFS="$IFS"
|
|
||||||
IFS=":,;-_, HhMmSs" read -r h m s <<<"$1"
|
|
||||||
IFS="$saveIFS"
|
|
||||||
else
|
|
||||||
h="$1"
|
|
||||||
m="$2"
|
|
||||||
s="$3"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo $((10#$h * 3600 + 10#$m * 60 + 10#$s))
|
|
||||||
}
|
|
||||||
|
|
||||||
_countdown_() {
|
|
||||||
# DESC: Sleep for a specified amount of time
|
|
||||||
# ARGS: $1 (Optional) - Total seconds to sleep for(Default is 10)
|
|
||||||
# $2 (Optional) - Increment to count down
|
|
||||||
# $3 (Optional) - Message to print at each increment (default is ...)
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: _countdown_ 10 1 "Waiting for cache to invalidate"
|
|
||||||
|
|
||||||
local i ii t
|
|
||||||
local n=${1:-10}
|
|
||||||
local stime=${2:-1}
|
|
||||||
local message="${3:-...}"
|
|
||||||
((t = n + 1))
|
|
||||||
|
|
||||||
for ((i = 1; i <= n; i++)); do
|
|
||||||
((ii = t - i))
|
|
||||||
if declare -f "info" &>/dev/null 2>&1; then
|
|
||||||
info "${message} ${ii}"
|
|
||||||
else
|
|
||||||
echo "${message} ${ii}"
|
|
||||||
fi
|
|
||||||
sleep $stime
|
|
||||||
done
|
|
||||||
}
|
|
||||||
@@ -1,148 +1,136 @@
|
|||||||
_haveInternet_() {
|
# Functions for working with network services
|
||||||
# DESC: Tests to see if there is an active Internet connection
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: _haveInternet_ && [SOMETHING]
|
|
||||||
# NOTE: https://stackoverflow.com/questions/929368/
|
|
||||||
|
|
||||||
if command -v fping &>/dev/null; then
|
|
||||||
fping 1.1.1.1 &>/dev/null \
|
|
||||||
&& return 0 \
|
|
||||||
|| return 1
|
|
||||||
elif ping -t 2 -c 1 1 1.1.1.1 &>/dev/null; then
|
|
||||||
return 0
|
|
||||||
elif command -v route &>/dev/null; then
|
|
||||||
local GATEWAY="$(route -n get default | grep gateway)"
|
|
||||||
ping -t 2 -c 1 "$(echo "${GATEWAY}" | cut -d ':' -f 2)" &>/dev/null \
|
|
||||||
&& return 0 \
|
|
||||||
|| return 1
|
|
||||||
elif command -v ip &>/dev/null; then
|
|
||||||
ping -t 2 -c 1 "$(ip r | grep default | cut -d ' ' -f 3)" &>/dev/null \
|
|
||||||
&& return 0 \
|
|
||||||
|| return 1
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_httpStatus_() {
|
_httpStatus_() {
|
||||||
# DESC: Report the HTTP status of a specified URL
|
# DESC:
|
||||||
# ARGS: $1 (Required) - URL (will work fine without https:// prefix)
|
# Report the HTTP status of a specified URL
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - URL (will work fine without https:// prefix)
|
||||||
# $2 (Optional) - Seconds to wait until timeout (Default is 3)
|
# $2 (Optional) - Seconds to wait until timeout (Default is 3)
|
||||||
# $3 (Optional) - either '--code' or '--status' (default)
|
# $3 (Optional) - either '--code' or '--status' (default)
|
||||||
# $4 (optional) - CURL opts separated by spaces (Use -L to follow redirects)
|
# $4 (optional) - CURL opts separated by spaces (Use -L to follow redirects)
|
||||||
# OUTS: Prints output to STDOUT
|
# OUTS:
|
||||||
# USAGE: _httpStatus_ URL [timeout] [--code or --status] [curl opts]
|
# stdout: Prints the HTTP status code or status message
|
||||||
# NOTE: https://gist.github.com/rsvp/1171304
|
# USAGE:
|
||||||
|
# _httpStatus_ URL [timeout] [--code or --status] [curl opts]
|
||||||
|
# NOTE:
|
||||||
|
# https://gist.github.com/rsvp/1171304
|
||||||
|
# EXAMPLES
|
||||||
|
# $ _httpStatus_ bit.ly
|
||||||
|
# 301 Redirection: Moved Permanently
|
||||||
#
|
#
|
||||||
# Example: $ _httpStatus_ bit.ly
|
# $ _httpStatus_ www.google.com 100 --code
|
||||||
# 301 Redirection: Moved Permanently
|
|
||||||
#
|
|
||||||
# Example: $ _httpStatus_ www.google.com 100 --code
|
|
||||||
local code
|
|
||||||
local status
|
|
||||||
|
|
||||||
local saveIFS=${IFS}
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _saveIFS=${IFS}
|
||||||
IFS=$' \n\t'
|
IFS=$' \n\t'
|
||||||
|
|
||||||
local url=${1:?_httpStatus_ needs an url}
|
local _url=${1}
|
||||||
local timeout=${2:-'3'}
|
local _timeout=${2:-3}
|
||||||
local flag=${3:-'--status'}
|
local _flag=${3:---status}
|
||||||
local arg4=${4:-''}
|
local _arg4=${4:-}
|
||||||
local arg5=${5:-''}
|
local _arg5=${5:-}
|
||||||
local arg6=${6:-''}
|
local _arg6=${6:-}
|
||||||
local arg7=${7:-''}
|
local _arg7=${7:-}
|
||||||
local curlops="${arg4} ${arg5} ${arg6} ${arg7}"
|
local _curlops="${_arg4} ${_arg5} ${_arg6} ${_arg7}"
|
||||||
|
local _code
|
||||||
|
local _status
|
||||||
|
|
||||||
# __________ get the CODE which is numeric:
|
# __________ get the CODE which is numeric:
|
||||||
code=$(echo "$(curl --write-out %{http_code} --silent --connect-timeout "${timeout}" \
|
_code=$(curl --write-out %{http_code} --silent --connect-timeout "${_timeout}" \
|
||||||
--no-keepalive "${curlops}" --output /dev/null "${url}")")
|
--no-keepalive ${_curlops} --output /dev/null ${_url})
|
||||||
|
|
||||||
# __________ get the STATUS (from code) which is human interpretable:
|
# __________ get the STATUS (from code) which is human interpretable:
|
||||||
case $code in
|
case $_code in
|
||||||
000) status="Not responding within ${timeout} seconds" ;;
|
000) _status="Not responding within ${_timeout} seconds" ;;
|
||||||
100) status="Informational: Continue" ;;
|
100) _status="Informational: Continue" ;;
|
||||||
101) status="Informational: Switching Protocols" ;;
|
101) _status="Informational: Switching Protocols" ;;
|
||||||
200) status="Successful: OK within ${timeout} seconds" ;;
|
200) _status="Successful: OK within ${_timeout} seconds" ;;
|
||||||
201) status="Successful: Created" ;;
|
201) _status="Successful: Created" ;;
|
||||||
202) status="Successful: Accepted" ;;
|
202) _status="Successful: Accepted" ;;
|
||||||
203) status="Successful: Non-Authoritative Information" ;;
|
203) _status="Successful: Non-Authoritative Information" ;;
|
||||||
204) status="Successful: No Content" ;;
|
204) _status="Successful: No Content" ;;
|
||||||
205) status="Successful: Reset Content" ;;
|
205) _status="Successful: Reset Content" ;;
|
||||||
206) status="Successful: Partial Content" ;;
|
206) _status="Successful: Partial Content" ;;
|
||||||
300) status="Redirection: Multiple Choices" ;;
|
300) _status="Redirection: Multiple Choices" ;;
|
||||||
301) status="Redirection: Moved Permanently" ;;
|
301) _status="Redirection: Moved Permanently" ;;
|
||||||
302) status="Redirection: Found residing temporarily under different URI" ;;
|
302) _status="Redirection: Found residing temporarily under different URI" ;;
|
||||||
303) status="Redirection: See Other" ;;
|
303) _status="Redirection: See Other" ;;
|
||||||
304) status="Redirection: Not Modified" ;;
|
304) _status="Redirection: Not Modified" ;;
|
||||||
305) status="Redirection: Use Proxy" ;;
|
305) _status="Redirection: Use Proxy" ;;
|
||||||
306) status="Redirection: status not defined" ;;
|
306) _status="Redirection: status not defined" ;;
|
||||||
307) status="Redirection: Temporary Redirect" ;;
|
307) _status="Redirection: Temporary Redirect" ;;
|
||||||
400) status="Client Error: Bad Request" ;;
|
400) _status="Client Error: Bad Request" ;;
|
||||||
401) status="Client Error: Unauthorized" ;;
|
401) _status="Client Error: Unauthorized" ;;
|
||||||
402) status="Client Error: Payment Required" ;;
|
402) _status="Client Error: Payment Required" ;;
|
||||||
403) status="Client Error: Forbidden" ;;
|
403) _status="Client Error: Forbidden" ;;
|
||||||
404) status="Client Error: Not Found" ;;
|
404) _status="Client Error: Not Found" ;;
|
||||||
405) status="Client Error: Method Not Allowed" ;;
|
405) _status="Client Error: Method Not Allowed" ;;
|
||||||
406) status="Client Error: Not Acceptable" ;;
|
406) _status="Client Error: Not Acceptable" ;;
|
||||||
407) status="Client Error: Proxy Authentication Required" ;;
|
407) _status="Client Error: Proxy Authentication Required" ;;
|
||||||
408) status="Client Error: Request Timeout within ${timeout} seconds" ;;
|
408) _status="Client Error: Request Timeout within ${_timeout} seconds" ;;
|
||||||
409) status="Client Error: Conflict" ;;
|
409) _status="Client Error: Conflict" ;;
|
||||||
410) status="Client Error: Gone" ;;
|
410) _status="Client Error: Gone" ;;
|
||||||
411) status="Client Error: Length Required" ;;
|
411) _status="Client Error: Length Required" ;;
|
||||||
412) status="Client Error: Precondition Failed" ;;
|
412) _status="Client Error: Precondition Failed" ;;
|
||||||
413) status="Client Error: Request Entity Too Large" ;;
|
413) _status="Client Error: Request Entity Too Large" ;;
|
||||||
414) status="Client Error: Request-URI Too Long" ;;
|
414) _status="Client Error: Request-URI Too Long" ;;
|
||||||
415) status="Client Error: Unsupported Media Type" ;;
|
415) _status="Client Error: Unsupported Media Type" ;;
|
||||||
416) status="Client Error: Requested Range Not Satisfiable" ;;
|
416) _status="Client Error: Requested Range Not Satisfiable" ;;
|
||||||
417) status="Client Error: Expectation Failed" ;;
|
417) _status="Client Error: Expectation Failed" ;;
|
||||||
500) status="Server Error: Internal Server Error" ;;
|
500) _status="Server Error: Internal Server Error" ;;
|
||||||
501) status="Server Error: Not Implemented" ;;
|
501) _status="Server Error: Not Implemented" ;;
|
||||||
502) status="Server Error: Bad Gateway" ;;
|
502) _status="Server Error: Bad Gateway" ;;
|
||||||
503) status="Server Error: Service Unavailable" ;;
|
503) _status="Server Error: Service Unavailable" ;;
|
||||||
504) status="Server Error: Gateway Timeout within ${timeout} seconds" ;;
|
504) _status="Server Error: Gateway Timeout within ${_timeout} seconds" ;;
|
||||||
505) status="Server Error: HTTP Version Not Supported" ;;
|
505) _status="Server Error: HTTP Version Not Supported" ;;
|
||||||
*) die "httpstatus: status not defined." ;;
|
*) fatal "httpstatus: status not defined." ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
case ${flag} in
|
case ${_flag} in
|
||||||
--status) echo "${code} ${status}" ;;
|
--status) echo "${_code} ${_status}" ;;
|
||||||
-s) echo "${code} ${status}" ;;
|
-s) echo "${_code} ${_status}" ;;
|
||||||
--code) echo "${code}" ;;
|
--code) echo "${_code}" ;;
|
||||||
-c) echo "${code}" ;;
|
-c) echo "${_code}" ;;
|
||||||
*) echo " httpstatus: bad flag" && _safeExit_ ;;
|
*) echo " _httpStatus_: bad flag" && _safeExit_ ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
IFS="${saveIFS}"
|
IFS="${_saveIFS}"
|
||||||
}
|
}
|
||||||
|
|
||||||
_pushover_() {
|
_pushover_() {
|
||||||
# DESC: Sends a notification via Pushover
|
# DESC:
|
||||||
# ARGS: $1 (Required) - Title of notification
|
# Sends a notification via Pushover
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Title of notification
|
||||||
# $2 (Required) - Body of notification
|
# $2 (Required) - Body of notification
|
||||||
# OUTS: None
|
# $3 (Required) - User Token
|
||||||
|
# $4 (Required) - API Key
|
||||||
|
# $5 (Optional) - Device
|
||||||
|
# OUTS:
|
||||||
|
# 0 if success
|
||||||
|
# 1 if failure
|
||||||
# USAGE: _pushover_ "Title Goes Here" "Message Goes Here"
|
# USAGE: _pushover_ "Title Goes Here" "Message Goes Here"
|
||||||
# NOTE: The variables for the two API Keys must have valid values
|
# NOTE: The variables for the two API Keys must have valid values
|
||||||
# Credit: http://ryonsherman.blogspot.com/2012/10/shell-script-to-send-pushover.html
|
# Credit: http://ryonsherman.blogspot.com/2012/10/shell-script-to-send-pushover.html
|
||||||
|
|
||||||
local PUSHOVERURL
|
[[ $# -lt 4 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
local API_KEY
|
|
||||||
local USER_KEY
|
|
||||||
local DEVICE
|
|
||||||
local TITLE
|
|
||||||
local MESSAGE
|
|
||||||
|
|
||||||
PUSHOVERURL="https://api.pushover.net/1/messages.json"
|
local _pushoverURL="https://api.pushover.net/1/messages.json"
|
||||||
API_KEY="${PUSHOVER_API_KEY}"
|
local _message="${2}"
|
||||||
USER_KEY="${PUSHOVER_USER_KEY}"
|
local _apiKey="${3}"
|
||||||
DEVICE=""
|
local _userKey="${4}"
|
||||||
TITLE="${1}"
|
local _device="${5:-}"
|
||||||
MESSAGE="${2}"
|
|
||||||
curl \
|
if curl \
|
||||||
-F "token=${API_KEY}" \
|
-F "token=${_apiKey}" \
|
||||||
-F "user=${USER_KEY}" \
|
-F "user=${_userKey}" \
|
||||||
-F "device=${DEVICE}" \
|
-F "device=${_device}" \
|
||||||
-F "title=${TITLE}" \
|
-F "title=${_messageTitle}" \
|
||||||
-F "message=${MESSAGE}" \
|
-F "message=${_message}" \
|
||||||
"${PUSHOVERURL}" >/dev/null 2>&1
|
"${_pushoverURL}" >/dev/null 2>&1; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
438
utilities/strings.bash
Normal file
438
utilities/strings.bash
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
# Transform text using these functions
|
||||||
|
# Some were adapted from https://github.com/jmcantrell/bashful
|
||||||
|
|
||||||
|
_cleanString_() {
|
||||||
|
# DESC:
|
||||||
|
# Cleans a string of text
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be cleaned
|
||||||
|
# $2 (optional) - Specific characters to be removed (separated by commas,
|
||||||
|
# escape regex special chars)
|
||||||
|
# OPTS:
|
||||||
|
# -l: Forces all text to lowercase
|
||||||
|
# -u: Forces all text to uppercase
|
||||||
|
# -a: Removes all non-alphanumeric characters except for spaces and dashes
|
||||||
|
# -p: Replace one character with another (separated by commas) (escape regex characters)
|
||||||
|
# -s: In combination with -a, replaces characters with a space
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints cleaned string
|
||||||
|
# USAGE:
|
||||||
|
# _cleanString_ [OPT] [STRING] [CHARS TO REMOVE]
|
||||||
|
# _cleanString_ -lp " ,-" [STRING] [CHARS TO REMOVE]
|
||||||
|
# NOTES:
|
||||||
|
# Always cleaned:
|
||||||
|
# - leading white space
|
||||||
|
# - trailing white space
|
||||||
|
# - multiple spaces become a single space
|
||||||
|
# - remove spaces before and after -_
|
||||||
|
|
||||||
|
local opt
|
||||||
|
local _lc=false
|
||||||
|
local _uc=false
|
||||||
|
local _alphanumeric=false
|
||||||
|
local _replace=false
|
||||||
|
local _us=false
|
||||||
|
|
||||||
|
local OPTIND=1
|
||||||
|
while getopts ":lLuUaAsSpP" opt; do
|
||||||
|
case $opt in
|
||||||
|
l | L) _lc=true ;;
|
||||||
|
u | U) _uc=true ;;
|
||||||
|
a | A) _alphanumeric=true ;;
|
||||||
|
s | S) _us=true ;;
|
||||||
|
p | P)
|
||||||
|
shift
|
||||||
|
declare -a _pairs=()
|
||||||
|
IFS=',' read -r -a _pairs <<<"$1"
|
||||||
|
_replace=true
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
{
|
||||||
|
error "Unrecognized option '$1' passed to _execute. Exiting."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _string="${1}"
|
||||||
|
local _userChars="${2:-}"
|
||||||
|
|
||||||
|
declare -a _arrayToClean=()
|
||||||
|
IFS=',' read -r -a _arrayToClean <<<"${_userChars}"
|
||||||
|
|
||||||
|
# trim trailing/leading white space and duplicate spaces/tabs
|
||||||
|
_string="$(echo "${_string}" | awk '{$1=$1};1')"
|
||||||
|
|
||||||
|
local i
|
||||||
|
for i in "${_arrayToClean[@]}"; do
|
||||||
|
debug "cleaning: $i"
|
||||||
|
_string="$(echo "${_string}" | sed "s/$i//g")"
|
||||||
|
done
|
||||||
|
|
||||||
|
("${_lc}") \
|
||||||
|
&& _string="$(echo "${_string}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
|
||||||
|
("${_uc}") \
|
||||||
|
&& _string="$(echo "${_string}" | tr '[:lower:]' '[:upper:]')"
|
||||||
|
|
||||||
|
if "${_alphanumeric}" && "${_us}"; then
|
||||||
|
_string="$(echo "${_string}" | tr -c '[:alnum:]_ -' ' ')"
|
||||||
|
elif "${_alphanumeric}"; then
|
||||||
|
_string="$(echo "${_string}" | sed "s/[^a-zA-Z0-9_ \-]//g")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if "${_replace}"; then
|
||||||
|
_string="$(echo "${_string}" | sed -E "s/${_pairs[0]}/${_pairs[1]}/g")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# trim trailing/leading white space and duplicate dashes
|
||||||
|
_string="$(echo "${_string}" | tr -s '-' | tr -s '_')"
|
||||||
|
_string="$(echo "${_string}" | sed -E 's/([_\-]) /\1/g' | sed -E 's/ ([_\-])/\1/g')"
|
||||||
|
_string="$(echo "${_string}" | awk '{$1=$1};1')"
|
||||||
|
|
||||||
|
echo "${_string}"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_decodeHTML_() {
|
||||||
|
# DESC:
|
||||||
|
# Decode HTML characters with sed. Utilizes a sed file for speed.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be decoded
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Error
|
||||||
|
# stdout: Prints decoded output
|
||||||
|
# USAGE:
|
||||||
|
# _decodeHTML_ <string>
|
||||||
|
# NOTE:
|
||||||
|
# Must have a sed file containing replacements. See: ../sedfiles/htmlDecode.sed
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _sedFile
|
||||||
|
_sedFile="${HOME}/.sed/htmlDecode.sed"
|
||||||
|
|
||||||
|
[ -f "${_sedFile}" ] \
|
||||||
|
&& { printf "%s\n" "${1}" | sed -f "${_sedFile}"; } \
|
||||||
|
|| return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_decodeURL_() {
|
||||||
|
# DESC:
|
||||||
|
# Decode a URL encoded string
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be decoded
|
||||||
|
# OUTS:
|
||||||
|
# Prints output to STDOUT
|
||||||
|
# USAGE:
|
||||||
|
# _decodeURL_ <string>
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _url_encoded="${1//+/ }"
|
||||||
|
printf '%b' "${_url_encoded//%/\\x}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_encodeHTML_() {
|
||||||
|
# DESC:
|
||||||
|
# Encode HTML characters with sed
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be encoded
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Error
|
||||||
|
# stdout: Prints encoded output
|
||||||
|
# USAGE:
|
||||||
|
# _encodeHTML_ <string>
|
||||||
|
# NOTE:
|
||||||
|
# Must have a sed file containing replacements. See: ../sedfiles/htmlEncode.sed
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _sedFile
|
||||||
|
_sedFile="${HOME}/.sed/htmlEncode.sed"
|
||||||
|
|
||||||
|
[ -f "${_sedFile}" ] \
|
||||||
|
&& { echo "${1}" | sed -f "${_sedFile}"; } \
|
||||||
|
|| return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_encodeURL_() {
|
||||||
|
# DESC:
|
||||||
|
# URL encode a string
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be encoded
|
||||||
|
# OUTS:
|
||||||
|
# Prints output to STDOUT
|
||||||
|
# USAGE:
|
||||||
|
# _encodeURL_ <string>
|
||||||
|
# CREDIT:
|
||||||
|
# https://gist.github.com/cdown/1163649
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local LANG=C
|
||||||
|
local i
|
||||||
|
|
||||||
|
for ((i = 0; i < ${#1}; i++)); do
|
||||||
|
if [[ ${1:i:1} =~ ^[a-zA-Z0-9\.\~_-]$ ]]; then
|
||||||
|
printf "${1:i:1}"
|
||||||
|
else
|
||||||
|
printf '%%%02X' "'${1:i:1}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
_escapeString_() {
|
||||||
|
# DESC:
|
||||||
|
# Escapes a string by adding \ before special chars
|
||||||
|
# ARGS:
|
||||||
|
# $@ (Required) - String to be escaped
|
||||||
|
# OUTS:
|
||||||
|
# stdout: Prints escaped output
|
||||||
|
# USAGE:
|
||||||
|
# _escapeString_ "Some text here"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
printf "%s\n" "${@}" | sed 's/[]\.|$[ (){}?+*^]/\\&/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
_lower_() {
|
||||||
|
# DESC:
|
||||||
|
# Convert a string to lowercase. Used through a pipe or here string.
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# text=$(_lower_ <<<"$1")
|
||||||
|
# echo "STRING" | _lower_
|
||||||
|
tr '[:upper:]' '[:lower:]'
|
||||||
|
}
|
||||||
|
|
||||||
|
_ltrim_() {
|
||||||
|
# DESC:
|
||||||
|
# Removes all leading whitespace (from the left). Used through a pipe or here string.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Optional) - Character to trim. Defaults to [:space:]
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# text=$(_ltrim_ <<<"$1")
|
||||||
|
# echo "STRING" | _ltrim_
|
||||||
|
local _char=${1:-[:space:]}
|
||||||
|
sed "s%^[${_char//%/\\%}]*%%"
|
||||||
|
}
|
||||||
|
|
||||||
|
_regexCapture_() {
|
||||||
|
# DESC:
|
||||||
|
# Use regex to validate and parse strings
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - Input String
|
||||||
|
# $2 (Required) - Regex pattern
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Regex matched
|
||||||
|
# 1 - Regex did not match
|
||||||
|
# stdout: Prints string matching regex
|
||||||
|
# USAGE:
|
||||||
|
# _regex_ "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
||||||
|
# NOTE:
|
||||||
|
# This example only prints the first matching group. When using multiple capture
|
||||||
|
# groups some modification is needed.
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/dylanaraps/pure-bash-bible
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
if [[ $1 =~ $2 ]]; then
|
||||||
|
printf '%s\n' "${BASH_REMATCH[1]}"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_rtrim_() {
|
||||||
|
# DESC:
|
||||||
|
# Removes all leading whitespace (from the right). Used through a pipe or here string.
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Optional) - Character to trim. Defaults to [:space:]
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# text=$(_rtrim_ <<<"$1")
|
||||||
|
# echo "STRING" | _rtrim_
|
||||||
|
local _char=${1:-[:space:]}
|
||||||
|
sed "s%[${_char//%/\\%}]*$%%"
|
||||||
|
}
|
||||||
|
|
||||||
|
_splitString_() {
|
||||||
|
# DESC:
|
||||||
|
# Splat a string into an array based on a given delimiter
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be split
|
||||||
|
# $2 (Required) - Delimiter
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Failure
|
||||||
|
# stdout: Values split by delimiter separated by newline
|
||||||
|
# USAGE:
|
||||||
|
# ARRAY=( $(_splitString_ "string1,string2,string3" ",") )
|
||||||
|
# CREDIT:
|
||||||
|
# https://github.com/labbots/bash-utility/blob/master/src/misc.sh
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
declare -a _arr=()
|
||||||
|
IFS=$'\n' read -d "" -ra _arr <<<"${1//$2/$'\n'}"
|
||||||
|
printf '%s\n' "${_arr[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_stringContains_() {
|
||||||
|
# DESC:
|
||||||
|
# Tests whether a string contains a substring
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be tested
|
||||||
|
# $2 (Required) - Substring to be tested for
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Search pattern found
|
||||||
|
# 1 - Pattern not found
|
||||||
|
# USAGE:
|
||||||
|
# _stringContains_ "Hello World!" "lo"
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
if [[ ${1} == *${2}* ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_stringRegex_() {
|
||||||
|
# DESC:
|
||||||
|
# Tests whether a string matches a regex pattern
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be tested
|
||||||
|
# $2 (Required) - Regex pattern to be tested for
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Search pattern found
|
||||||
|
# 1 - Pattern not found
|
||||||
|
# USAGE:
|
||||||
|
# _stringContains_ "HELLO" "^[A-Z]*$"
|
||||||
|
|
||||||
|
[[ $# -lt 2 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
if [[ ${1} =~ ${2} ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_stripStopwords_() {
|
||||||
|
# DESC:
|
||||||
|
# Removes common stopwords from a string using a list of sed replacements located
|
||||||
|
# in an external file. Additional stopwords can be added in arg2
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to parse
|
||||||
|
# $2 (Optional) - Additional stopwords (comma separated)
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Error
|
||||||
|
# stdout: Prints string cleaned of stopwords
|
||||||
|
# USAGE:
|
||||||
|
# CLEAN_WORD="$(_stripStopwords_ "[STRING]" "[MORE,STOP,WORDS]")"
|
||||||
|
# NOTE:
|
||||||
|
# Must have a sed file containing replacements. See: ../sedfiles/stopwords.sed
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
if ! sed --version | grep GNU &>/dev/null; then
|
||||||
|
fatal "_stripStopwords_: Required GNU sed not found. Exiting."
|
||||||
|
fi
|
||||||
|
|
||||||
|
local _string="${1}"
|
||||||
|
local _sedFile="${HOME}/.sed/stopwords.sed"
|
||||||
|
local _w
|
||||||
|
|
||||||
|
if [ -f "${_sedFile}" ]; then
|
||||||
|
_string="$(echo "${_string}" | sed -f "${_sedFile}")"
|
||||||
|
else
|
||||||
|
fatal "_stripStopwords_: Missing sedfile expected at: ${_sedFile}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
declare -a _localStopWords=()
|
||||||
|
IFS=',' read -r -a _localStopWords <<<"${2:-}"
|
||||||
|
|
||||||
|
if [[ ${#_localStopWords[@]} -gt 0 ]]; then
|
||||||
|
for _w in "${_localStopWords[@]}"; do
|
||||||
|
_string="$(echo "${_string}" | sed -E "s/\b${_w}\b//gI")"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove double spaces and trim left/right
|
||||||
|
_string="$(echo "${_string}" | sed -E 's/[ ]{2,}/ /g' | _trim_)"
|
||||||
|
|
||||||
|
printf "%s\n" "${_string}"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_stripANSI_() {
|
||||||
|
# DESC:
|
||||||
|
# Strips ANSI escape sequences from a string
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Required) - String to be cleaned
|
||||||
|
# OUTS:
|
||||||
|
# 0 - Success
|
||||||
|
# 1 - Failure
|
||||||
|
# stdout: Prints string with ANSI escape sequences removed
|
||||||
|
# USAGE:
|
||||||
|
# _stripANSI_ "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text.\e(B\e[m"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
local _tmp
|
||||||
|
local _esc
|
||||||
|
local _tpa
|
||||||
|
local _re
|
||||||
|
_tmp="${1}"
|
||||||
|
_esc=$(printf "\x1b")
|
||||||
|
_tpa=$(printf "\x28")
|
||||||
|
_re="(.*)${_esc}[\[${_tpa}][0-9]*;*[mKB](.*)"
|
||||||
|
while [[ ${_tmp} =~ ${_re} ]]; do
|
||||||
|
_tmp="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
|
||||||
|
done
|
||||||
|
printf "%s" "${_tmp}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_trim_() {
|
||||||
|
# DESC:
|
||||||
|
# Removes all leading/trailing whitespace. Used through a pipe or here string.
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# text=$(_trim_ <<<"$1")
|
||||||
|
# echo "STRING" | _trim_
|
||||||
|
awk '{$1=$1;print}'
|
||||||
|
}
|
||||||
|
|
||||||
|
_upper_() {
|
||||||
|
# DESC:
|
||||||
|
# Convert a string to uppercase. Used through a pipe or here string.
|
||||||
|
# ARGS:
|
||||||
|
# None
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
# USAGE:
|
||||||
|
# text=$(_upper_ <<<"$1")
|
||||||
|
# echo "STRING" | _upper_
|
||||||
|
tr '[:lower:]' '[:upper:]'
|
||||||
|
}
|
||||||
119
utilities/template_utils.bash
Normal file
119
utilities/template_utils.bash
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# Functions required to allow the script template and alert functions to be used
|
||||||
|
|
||||||
|
_acquireScriptLock_() {
|
||||||
|
# DESC:
|
||||||
|
# Acquire script lock to prevent running the same script a second time before the
|
||||||
|
# first instance exits
|
||||||
|
# ARGS:
|
||||||
|
# $1 (optional) - Scope of script execution lock (system or user)
|
||||||
|
# OUTS:
|
||||||
|
# exports $SCRIPT_LOCK - Path to the directory indicating we have the script lock
|
||||||
|
# Exits script if lock cannot be acquired
|
||||||
|
# NOTE:
|
||||||
|
# If the lock was acquired it's automatically released in _safeExit_()
|
||||||
|
|
||||||
|
local _lockDir
|
||||||
|
if [[ ${1:-} == 'system' ]]; then
|
||||||
|
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
|
||||||
|
else
|
||||||
|
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
|
||||||
|
readonly SCRIPT_LOCK="${_lockDir}"
|
||||||
|
debug "Acquired script lock: ${tan}${SCRIPT_LOCK}${purple}"
|
||||||
|
else
|
||||||
|
if [ "$(declare -f "_safeExit_")" ]; then
|
||||||
|
error "Unable to acquire script lock: ${yellow}${LOCK_DIR}${red}"
|
||||||
|
fatal "If you trust the script isn't running, delete the lock dir"
|
||||||
|
else
|
||||||
|
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${LOCK_DIR}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_makeTempDir_() {
|
||||||
|
# DESC:
|
||||||
|
# Creates a temp directory to house temporary files
|
||||||
|
# ARGS:
|
||||||
|
# $1 (Optional) - First characters/word of directory name
|
||||||
|
# OUTS:
|
||||||
|
# Sets $TMP_DIR variable to the path of the temp directory
|
||||||
|
# USAGE:
|
||||||
|
# _makeTempDir_ "$(basename "$0")"
|
||||||
|
|
||||||
|
[ -d "${TMP_DIR:-}" ] && return 0
|
||||||
|
|
||||||
|
if [ -n "${1:-}" ]; then
|
||||||
|
TMP_DIR="${TMPDIR:-/tmp/}${1}.${RANDOM}.${RANDOM}.$$"
|
||||||
|
else
|
||||||
|
TMP_DIR="${TMPDIR:-/tmp/}$(basename "$0").${RANDOM}.${RANDOM}.${RANDOM}.$$"
|
||||||
|
fi
|
||||||
|
(umask 077 && mkdir "${TMP_DIR}") || {
|
||||||
|
fatal "Could not create temporary directory! Exiting."
|
||||||
|
}
|
||||||
|
debug "\$TMP_DIR=${TMP_DIR}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_safeExit_() {
|
||||||
|
# DESC:
|
||||||
|
# Cleanup and exit from a script
|
||||||
|
# ARGS:
|
||||||
|
# $1 (optional) - Exit code (defaults to 0)
|
||||||
|
# OUTS:
|
||||||
|
# None
|
||||||
|
|
||||||
|
if [[ -d ${SCRIPT_LOCK:-} ]]; then
|
||||||
|
if command rm -rf "${SCRIPT_LOCK}"; then
|
||||||
|
debug "Removing script lock"
|
||||||
|
else
|
||||||
|
warning "Script lock could not be removed. Try manually deleting ${yellow}'${LOCK_DIR}'"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n ${TMP_DIR:-} && -d ${TMP_DIR:-} ]]; then
|
||||||
|
if [[ ${1:-} == 1 && -n "$(ls "${TMP_DIR}")" ]]; then
|
||||||
|
command rm -r "${TMP_DIR}"
|
||||||
|
else
|
||||||
|
command rm -r "${TMP_DIR}"
|
||||||
|
debug "Removing temp directory"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
trap - INT TERM EXIT
|
||||||
|
exit ${1:-0}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setPATH_() {
|
||||||
|
# DESC:
|
||||||
|
# Add directories to $PATH so script can find executables
|
||||||
|
# ARGS:
|
||||||
|
# $@ - One or more paths
|
||||||
|
# OUTS: Adds items to $PATH
|
||||||
|
# USAGE:
|
||||||
|
# _setPATH_ "/usr/local/bin" "${HOME}/bin" "$(npm bin)"
|
||||||
|
|
||||||
|
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
|
||||||
|
|
||||||
|
local _newPath
|
||||||
|
|
||||||
|
for _newPath in "$@"; do
|
||||||
|
if [ -d "${_newPath}" ]; then
|
||||||
|
if ! echo "${PATH}" | grep -Eq "(^|:)${_newPath}($|:)"; then
|
||||||
|
if PATH="${_newPath}:${PATH}"; then
|
||||||
|
debug "Added '${_newPath}' to PATH"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
debug "_setPATH_: '${_newPath}' already exists in PATH"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
debug "_setPATH_: can not find: ${_newPath}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
# Transform text using these functions
|
|
||||||
# Some were adapted from https://github.com/jmcantrell/bashful
|
|
||||||
|
|
||||||
_cleanString_() {
|
|
||||||
# DESC: Cleans a string of text
|
|
||||||
# ARGS: $1 (Required) - String to be cleaned
|
|
||||||
# $2 (optional) - Specific characters to be removed (separated by commas,
|
|
||||||
# escape regex special chars)
|
|
||||||
# OPTS: -l Forces all text to lowercase
|
|
||||||
# -u Forces all text to uppercase
|
|
||||||
# -a Removes all non-alphanumeric characters except for spaces and dashes
|
|
||||||
# -p Replace one character with another (separated by commas) (escape regex characters)
|
|
||||||
# -s In combination with -a, replaces characters with a space
|
|
||||||
# OUTS: Prints result to STDOUT
|
|
||||||
# USAGE: _cleanString_ [OPT] [STRING] [CHARS TO REMOVE]
|
|
||||||
# _cleanString_ -lp " ,-" [STRING] [CHARS TO REMOVE]
|
|
||||||
# NOTES: Always cleaned:
|
|
||||||
# - leading white space
|
|
||||||
# - trailing white space
|
|
||||||
# - multiple spaces become a single space
|
|
||||||
# - remove spaces before and after -_
|
|
||||||
|
|
||||||
local opt
|
|
||||||
local lc=false
|
|
||||||
local uc=false
|
|
||||||
local alphanumeric=false
|
|
||||||
local replace=false
|
|
||||||
local us=false
|
|
||||||
|
|
||||||
local OPTIND=1
|
|
||||||
while getopts ":lLuUaAsSpP" opt; do
|
|
||||||
case $opt in
|
|
||||||
l | L) lc=true ;;
|
|
||||||
u | U) uc=true ;;
|
|
||||||
a | A) alphanumeric=true ;;
|
|
||||||
s | S) us=true ;;
|
|
||||||
p | P)
|
|
||||||
shift
|
|
||||||
local pairs=()
|
|
||||||
IFS=',' read -r -a pairs <<<"$1"
|
|
||||||
replace=true
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
{
|
|
||||||
error "Unrecognized option '$1' passed to _execute. Exiting."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && fatal 'Missing required argument to _cleanString_()!'
|
|
||||||
|
|
||||||
local string="${1}"
|
|
||||||
local userChars="${2:-}"
|
|
||||||
|
|
||||||
local arrayToClean=()
|
|
||||||
IFS=',' read -r -a arrayToClean <<<"${userChars}"
|
|
||||||
|
|
||||||
# trim trailing/leading white space and duplicate spaces/tabs
|
|
||||||
string="$(echo "${string}" | awk '{$1=$1};1')"
|
|
||||||
|
|
||||||
local i
|
|
||||||
for i in "${arrayToClean[@]}"; do
|
|
||||||
debug "cleaning: $i"
|
|
||||||
string="$(echo "${string}" | sed "s/$i//g")"
|
|
||||||
done
|
|
||||||
|
|
||||||
("${lc}") \
|
|
||||||
&& string="$(echo "${string}" | tr '[:upper:]' '[:lower:]')"
|
|
||||||
|
|
||||||
("${uc}") \
|
|
||||||
&& string="$(echo "${string}" | tr '[:lower:]' '[:upper:]')"
|
|
||||||
|
|
||||||
if "${alphanumeric}" && "${us}"; then
|
|
||||||
string="$(echo "${string}" | tr -c '[:alnum:]_ -' ' ')"
|
|
||||||
elif "${alphanumeric}"; then
|
|
||||||
string="$(echo "${string}" | sed "s/[^a-zA-Z0-9_ \-]//g")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if "${replace}"; then
|
|
||||||
string="$(echo "${string}" | sed -E "s/${pairs[0]}/${pairs[1]}/g")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# trim trailing/leading white space and duplicate dashes
|
|
||||||
string="$(echo "${string}" | tr -s '-' | tr -s '_')"
|
|
||||||
string="$(echo "${string}" | sed -E 's/([_\-]) /\1/g' | sed -E 's/ ([_\-])/\1/g')"
|
|
||||||
string="$(echo "${string}" | awk '{$1=$1};1')"
|
|
||||||
|
|
||||||
echo "${string}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_stopWords_() {
|
|
||||||
# DESC: Removes common stopwords from a string
|
|
||||||
# ARGS: $1 (Required) - String to parse
|
|
||||||
# $2 (Optional) - Additional stopwords (comma separated)
|
|
||||||
# OUTS: Prints cleaned string to STDOUT
|
|
||||||
# USAGE: cleanName="$(_stopWords_ "[STRING]" "[MORE,STOP,WORDS]")"
|
|
||||||
# NOTE: Requires a stopwords file in sed format (expected at: ~/.sed/stopwords.sed)
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && {
|
|
||||||
warning 'Missing required argument to _stripCommonWords_!'
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if command -v gsed &>/dev/null; then
|
|
||||||
local SED_COMMAND="gsed"
|
|
||||||
elif sed --version | grep GNU &>/dev/null; then
|
|
||||||
local SED_COMMAND="sed"
|
|
||||||
else
|
|
||||||
error "Can not continue without gnu sed. Use '${yellow}brew install gnu-sed${reset} on a Mac or install with your package manager'"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local string="${1}"
|
|
||||||
local sedFile="${HOME}/.sed/stopwords.sed"
|
|
||||||
if [ -f "${sedFile}" ]; then
|
|
||||||
string="$(echo "${string}" | ${SED_COMMAND} -f "${sedFile}")"
|
|
||||||
else
|
|
||||||
error "Missing sedfile in _stopWords_()"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
declare -a localStopWords=()
|
|
||||||
IFS=',' read -r -a localStopWords <<<"${2:-}"
|
|
||||||
|
|
||||||
if [[ ${#localStopWords[@]} -gt 0 ]]; then
|
|
||||||
for w in "${localStopWords[@]}"; do
|
|
||||||
string="$(echo "${string}" | ${SED_COMMAND} -E "s/\b${w}\b//gI")"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove double spaces and trim left/right
|
|
||||||
string="$(echo "${string}" | ${SED_COMMAND} -E 's/[ ]{2,}/ /g' | _ltrim_ | _rtrim_)"
|
|
||||||
|
|
||||||
echo "${string}"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_escape_() {
|
|
||||||
# DESC: Escapes a string by adding \ before special chars
|
|
||||||
# ARGS: $@ (Required) - String to be escaped
|
|
||||||
# OUTS: Prints output to STDOUT
|
|
||||||
# USAGE: _escape_ "Some text here"
|
|
||||||
|
|
||||||
# shellcheck disable=2001
|
|
||||||
echo "${@}" | sed 's/[]\.|$[ (){}?+*^]/\\&/g'
|
|
||||||
}
|
|
||||||
|
|
||||||
_htmlDecode_() {
|
|
||||||
# DESC: Decode HTML characters with sed
|
|
||||||
# ARGS: $1 (Required) - String to be decoded
|
|
||||||
# OUTS: Prints output to STDOUT
|
|
||||||
# USAGE: _htmlDecode_ <string>
|
|
||||||
# NOTE: Must have a sed file containing replacements
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && {
|
|
||||||
error 'Missing required argument to _htmlDecode_()!'
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local sedFile
|
|
||||||
sedFile="${HOME}/.sed/htmlDecode.sed"
|
|
||||||
|
|
||||||
[ -f "${sedFile}" ] \
|
|
||||||
&& { echo "${1}" | sed -f "${sedFile}"; } \
|
|
||||||
|| return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_htmlEncode_() {
|
|
||||||
# DESC: Encode HTML characters with sed
|
|
||||||
# ARGS: $1 (Required) - String to be encoded
|
|
||||||
# OUTS: Prints output to STDOUT
|
|
||||||
# USAGE: _htmlEncode_ <string>
|
|
||||||
# NOTE: Must have a sed file containing replacements
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && {
|
|
||||||
error 'Missing required argument to _htmlEncode_()!'
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local sedFile
|
|
||||||
sedFile="${HOME}/.sed/htmlEncode.sed"
|
|
||||||
|
|
||||||
[ -f "${sedFile}" ] \
|
|
||||||
&& { echo "${1}" | sed -f "${sedFile}"; } \
|
|
||||||
|| return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_lower_() {
|
|
||||||
# DESC: Convert a string to lowercase
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: text=$(_lower_ <<<"$1")
|
|
||||||
# echo "STRING" | _lower_
|
|
||||||
tr '[:upper:]' '[:lower:]'
|
|
||||||
}
|
|
||||||
|
|
||||||
_upper_() {
|
|
||||||
# DESC: Convert a string to uppercase
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: text=$(_upper_ <<<"$1")
|
|
||||||
# echo "STRING" | _upper_
|
|
||||||
tr '[:lower:]' '[:upper:]'
|
|
||||||
}
|
|
||||||
|
|
||||||
_ltrim_() {
|
|
||||||
# DESC: Removes all leading whitespace (from the left)
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: text=$(_ltrim_ <<<"$1")
|
|
||||||
# echo "STRING" | _ltrim_
|
|
||||||
local char=${1:-[:space:]}
|
|
||||||
sed "s%^[${char//%/\\%}]*%%"
|
|
||||||
}
|
|
||||||
|
|
||||||
_regex_() {
|
|
||||||
# DESC: Use regex to validate and parse strings
|
|
||||||
# ARGS: $1 (Required) - Input String
|
|
||||||
# $2 (Required) - Regex pattern
|
|
||||||
# OUTS: Prints string matching regex
|
|
||||||
# Returns error if no part of string did not match regex
|
|
||||||
# USAGE: _regex_ "#FFFFFF" '^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$'
|
|
||||||
# NOTE: This example only prints the first matching group. When using multiple capture
|
|
||||||
# groups some modification is needed.
|
|
||||||
# https://github.com/dylanaraps/pure-bash-bible
|
|
||||||
if [[ $1 =~ $2 ]]; then
|
|
||||||
printf '%s\n' "${BASH_REMATCH[1]}"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_rtrim_() {
|
|
||||||
# DESC: Removes all leading whitespace (from the right)
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: text=$(_rtrim_ <<<"$1")
|
|
||||||
# echo "STRING" | _rtrim_
|
|
||||||
local char=${1:-[:space:]}
|
|
||||||
sed "s%[${char//%/\\%}]*$%%"
|
|
||||||
}
|
|
||||||
|
|
||||||
_trim_() {
|
|
||||||
# DESC: Removes all leading/trailing whitespace
|
|
||||||
# ARGS: None
|
|
||||||
# OUTS: None
|
|
||||||
# USAGE: text=$(_trim_ <<<"$1")
|
|
||||||
# echo "STRING" | _trim_
|
|
||||||
awk '{$1=$1;print}'
|
|
||||||
}
|
|
||||||
|
|
||||||
_urlEncode_() {
|
|
||||||
# DESC: URL encode a string
|
|
||||||
# ARGS: $1 (Required) - String to be encoded
|
|
||||||
# OUTS: Prints output to STDOUT
|
|
||||||
# USAGE: _urlEncode_ <string>
|
|
||||||
# NOTE: https://gist.github.com/cdown/1163649
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && {
|
|
||||||
error 'Missing required argument to _urlEncode_()!'
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local LANG=C
|
|
||||||
local i
|
|
||||||
|
|
||||||
for ((i = 0; i < ${#1}; i++)); do
|
|
||||||
if [[ ${1:i:1} =~ ^[a-zA-Z0-9\.\~_-]$ ]]; then
|
|
||||||
printf "${1:i:1}"
|
|
||||||
else
|
|
||||||
printf '%%%02X' "'${1:i:1}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
_urlDecode_() {
|
|
||||||
# DESC: Decode a URL encoded string
|
|
||||||
# ARGS: $1 (Required) - String to be decoded
|
|
||||||
# OUTS: Prints output to STDOUT
|
|
||||||
# USAGE: _urlDecode_ <string>
|
|
||||||
|
|
||||||
[[ $# -lt 1 ]] && {
|
|
||||||
error 'Missing required argument to _urlDecode_()!'
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
local url_encoded="${1//+/ }"
|
|
||||||
printf '%b' "${url_encoded//%/\\x}"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user