shellcheck improvements

This commit is contained in:
Nathaniel Landau
2021-10-29 15:01:31 -04:00
parent 86300b68c4
commit 1377697ae6
15 changed files with 196 additions and 197 deletions

View File

@@ -436,7 +436,6 @@ _setColors_() {
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)
@@ -445,7 +444,6 @@ _setColors_() {
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)
@@ -460,7 +458,6 @@ _setColors_() {
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"
@@ -648,7 +645,7 @@ _safeExit_() {
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}'"
warning "Script lock could not be removed. Try manually deleting ${yellow}'${SCRIPT_LOCK}'"
fi
fi
@@ -730,6 +727,7 @@ _makeTempDir_() {
debug "\$TMP_DIR=${TMP_DIR}"
}
# shellcheck disable=SC2120
_acquireScriptLock_() {
# DESC:
# Acquire script lock to prevent running the same script a second time before the
@@ -746,18 +744,18 @@ _acquireScriptLock_() {
if [[ ${1:-} == 'system' ]]; then
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
else
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").${UID}.lock"
fi
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
if command mkdir "${_lockDir}" 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}"
if declare -f "_safeExit_" &>/dev/null; then
error "Unable to acquire script lock: ${yellow}${_lockDir}${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}"
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${_lockDir}"
exit 1
fi

View File

@@ -14,6 +14,7 @@ _mainScript_() {
input "This is input text"
}
#/_mainsScript_()
# ################################## Flags and defaults
@@ -52,7 +53,7 @@ _trapCleanup_() {
local _script="${5:-}"
local _sourced="${6:-}"
if [[ "$(declare -f "fatal")" && "$(declare -f "_printFuncStack_")" ]]; then
if declare -f "fatal" &>/dev/null && declare -f "_printFuncStack_" &>/dev/null; then
_funcstack="'$(printf "%s" "${_funcstack}" | sed -E 's/ / < /g')'"
@@ -65,7 +66,7 @@ _trapCleanup_() {
printf "%s\n" "Fatal error trapped. Exiting..."
fi
if [ "$(declare -f "_safeExit_")" ]; then
if declare -f _safeExit_ &>/dev/null; then
_safeExit_ 1
else
exit 1
@@ -87,9 +88,11 @@ _findBaseDir_() {
local _dir
# Is file sourced?
[[ $_ != "$0" ]] \
&& _source="${BASH_SOURCE[1]}" \
|| _source="${BASH_SOURCE[0]}"
if [[ ${_} != "${0}" ]]; then
_source="${BASH_SOURCE[1]}"
else
_source="${BASH_SOURCE[0]}"
fi
while [ -h "${_source}" ]; do # Resolve $SOURCE until the file is no longer a symlink
_dir="$(cd -P "$(dirname "${_source}")" && pwd)"
@@ -104,93 +107,92 @@ _sourceUtilities_() {
# Sources utility functions. Absolute paths are required for shellcheck to correctly
# parse the sourced files
# ARGS:
# NONE
# $1 (Required): Absolute path to the directory containing the utilities
# OUTS:
# 0: Success
# 1: Failure
# USAGE:
# _sourceUtilities_
# _sourceUtilities_ "$(_findBaseDir_)/../../shell-scripting-templates/utilities"
local _utilsPath
_utilsPath="$(_findBaseDir_)/../shell-scripting-templates/utilities/"
_utilsPath="${1}"
if [ -f "${_utilsPath}/alerts.bash" ]; then
source "${_utilsPath}/alerts.bash"
else
printf "%s\n" "ERROR: alerts.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/alerts.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/arrays.bash" ]; then
source "${_utilsPath}/arrays.bash"
else
printf "%s\n" "ERROR: arrays.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/arrays.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/checks.bash" ]; then
source "${_utilsPath}/checks.bash"
else
printf "%s\n" "ERROR: checks.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/checks.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/dates.bash" ]; then
source "${_utilsPath}/dates.bash"
else
printf "%s\n" "ERROR: dates.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/dates.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/debug.bash" ]; then
source "${_utilsPath}/debug.bash"
else
printf "%s\n" "ERROR: debug.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/debug.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/files.bash" ]; then
source "${_utilsPath}/files.bash"
else
printf "%s\n" "ERROR: files.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/files.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/macOS.bash" ]; then
source "${_utilsPath}/macOS.bash"
else
printf "%s\n" "ERROR: macOS.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/macOS.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/misc.bash" ]; then
source "${_utilsPath}/misc.bash"
else
printf "%s\n" "ERROR: misc.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/misc.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/services.bash" ]; then
source "${_utilsPath}/services.bash"
else
printf "%s\n" "ERROR: services.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/services.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/strings.bash" ]; then
source "${_utilsPath}/strings.bash"
else
printf "%s\n" "ERROR: strings.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/strings.bash not found"
exit 1
fi
if [ -f "${_utilsPath}/template_utils.bash" ]; then
source "${_utilsPath}/template_utils.bash"
else
printf "%s\n" "ERROR: template_utils.bash not found"
printf "%s\n" "ERROR: ${_utilsPath}/template_utils.bash not found"
exit 1
fi
}
_parseOptions_() {
@@ -219,7 +221,7 @@ _parseOptions_() {
_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
if [[ ${_optstring} == *"${_c}:"* && -n ${1:i+1} ]]; then
_options+=("${1:i+1}")
break
fi
@@ -265,10 +267,10 @@ _parseOptions_() {
break
;;
*)
if [ "$(declare -f "_safeExit_")" ]; then
if declare -f _safeExit_ &>/dev/null; then
fatal "invalid option: $1"
else
printf "%s\n" "Invalid option: $1"
printf "%s\n" "ERROR: Invalid option: $1"
exit 1
fi
;;
@@ -337,7 +339,7 @@ IFS=$' \n\t'
# set -o xtrace
# Source utility functions
_sourceUtilities_
_sourceUtilities_ "$(_findBaseDir_)/../shell-scripting-templates/utilities"
# Initialize color constants
_setColors_

View File

@@ -52,7 +52,6 @@ _setColors_() {
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)
@@ -61,7 +60,6 @@ _setColors_() {
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)
@@ -76,7 +74,6 @@ _setColors_() {
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"
@@ -241,10 +238,17 @@ _printFuncStack_() {
# NOTE:
# Does not print functions from the alert class
local _i
_funcStackResponse=()
declare -a _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]}")
case "${FUNCNAME[${_i}]}" in
_alert_ | _trapCleanup_ | fatal | error | warning | notice | info | debug | dryrun | header | success)
continue
;;
*)
_funcStackResponse+=("${FUNCNAME[${_i}]}:$(basename "${BASH_SOURCE[${_i}]}"):${BASH_LINENO[_i - 1]}")
;;
esac
done
printf "( "
printf %s "${_funcStackResponse[0]}"
@@ -264,7 +268,7 @@ _safeExit_() {
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}'"
warning "Script lock could not be removed. Try manually deleting ${yellow}'${SCRIPT_LOCK}'"
fi
fi
@@ -303,7 +307,7 @@ _trapCleanup_() {
local _script="${5:-}"
local _sourced="${6:-}"
if [[ "$(declare -f "fatal")" && "$(declare -f "_printFuncStack_")" ]]; then
if declare -f "fatal" &>/dev/null && declare -f "_printFuncStack_" &>/dev/null; then
_funcstack="'$(printf "%s" "${_funcstack}" | sed -E 's/ / < /g')'"
@@ -316,7 +320,7 @@ _trapCleanup_() {
printf "%s\n" "Fatal error trapped. Exiting..."
fi
if [ "$(declare -f "_safeExit_")" ]; then
if declare -f _safeExit_ &>/dev/null; then
_safeExit_ 1
else
exit 1
@@ -346,6 +350,7 @@ _makeTempDir_() {
debug "\$TMP_DIR=${TMP_DIR}"
}
# shellcheck disable=SC2120
_acquireScriptLock_() {
# DESC:
# Acquire script lock to prevent running the same script a second time before the
@@ -362,18 +367,18 @@ _acquireScriptLock_() {
if [[ ${1:-} == 'system' ]]; then
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
else
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").${UID}.lock"
fi
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
if command mkdir "${_lockDir}" 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}"
if declare -f "_safeExit_" &>/dev/null; then
error "Unable to acquire script lock: ${yellow}${_lockDir}${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}"
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${_lockDir}"
exit 1
fi
@@ -426,7 +431,7 @@ _useGNUutils_() {
# NOTES:
# GNU utilities can be added to MacOS using Homebrew
[ ! "$(declare -f "_setPATH_")" ] && fatal "${FUNCNAME[0]} needs function _setPATH_"
! declare -f "_setPATH_" &>/dev/null && fatal "${FUNCNAME[0]} needs function _setPATH_"
if _setPATH_ \
"/usr/local/opt/gnu-tar/libexec/gnubin" \
@@ -466,7 +471,7 @@ _parseOptions_() {
_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
if [[ ${_optstring} == *"${_c}:"* && -n ${1:i+1} ]]; then
_options+=("${1:i+1}")
break
fi
@@ -512,10 +517,10 @@ _parseOptions_() {
break
;;
*)
if [ "$(declare -f "_safeExit_")" ]; then
if declare -f _safeExit_ &>/dev/null; then
fatal "invalid option: $1"
else
printf "%s\n" "Invalid option: $1"
printf "%s\n" "ERROR: Invalid option: $1"
exit 1
fi
;;

52
test/fixtures/test.md vendored
View File

@@ -1,20 +1,22 @@
# About
This repository contains everything needed to bootstrap and configure new Mac computer. Included here are:
* dotfiles
* ~/bin/ scripts
* Configuration files
* Scripting templates and utilities
* `install.sh`, a script to put everything where it needs to go
- dotfiles
- ~/bin/ scripts
- Configuration files
- Scripting templates and utilities
- `install.sh`, a script to put everything where it needs to go
**Disclaimer:** *I am not a professional programmer and I bear no responsibility whatsoever if any of these scripts wipes your computer, destroys your data, crashes your car, or otherwise causes mayhem and destruction. USE AT YOUR OWN RISK.*
**Disclaimer:** _I am not a professional programmer and I bear no responsibility whatsoever if any of these scripts wipes your computer, destroys your data, crashes your car, or otherwise causes mayhem and destruction. USE AT YOUR OWN RISK._
## install.sh
This script runs through a series of tasks to configure a new computer. There are three distinct areas of `install.sh` which are executed in order. These are:
1. **Bootstrapping** - Installing base components such as Command Line Tools, Homebrew, Node, RVM, etc.
2. **Installation** - Symlinking dotfiles and installing executables such as NPM Packages, Homebrew Casks, etc.
3. **Configuration** - Configures installed packages and apps.
1. **Bootstrapping** - Installing base components such as Command Line Tools, Homebrew, Node, RVM, etc.
2. **Installation** - Symlinking dotfiles and installing executables such as NPM Packages, Homebrew Casks, etc.
3. **Configuration** - Configures installed packages and apps.
The files are organized into three subdirectories.
@@ -32,20 +34,20 @@ dotfiles
└── scripting/
```
* **bin** - Symlinked to `~/bin` and is added to your `$PATH`.
* **config** - Contains the elements needed to configure your environment and specific apps.
* config/**bash** - Files in this directory are *sourced* by `.bash_profile`.
* config/**shell** - Files here are symlinked to your local environment. Ahem, dotfiles.
* **lib** - Contains the scripts and configuration for `install.sh`
* lib/**bootstrap** - Scripts here are executed by `install.sh` first.
* lib/**configure** - Scripts here are exectuted by `install.sh` after packages have been installed
* **config-install.yaml** - This YAML file contains the list of symlinks to be created, as well as the packages to be installed.
* **scripting** - This directory contains bash scripting utilities and templates which I re-use often.
- **bin** - Symlinked to `~/bin` and is added to your `$PATH`.
- **config** - Contains the elements needed to configure your environment and specific apps.
- config/**bash** - Files in this directory are _sourced_ by `.bash_profile`.
- config/**shell** - Files here are symlinked to your local environment. Ahem, dotfiles.
- **lib** - Contains the scripts and configuration for `install.sh`
- lib/**bootstrap** - Scripts here are executed by `install.sh` first.
- lib/**configure** - Scripts here are executed by `install.sh` after packages have been installed
- **config-install.yaml** - This YAML file contains the list of symlinks to be created, as well as the packages to be installed.
- **scripting** - This directory contains bash scripting utilities and templates which I re-use often.
**IMPORTANT:** Unless you want to use my defaults, make sure you do the following:
* Edit `config-install.yaml` to reflect your preferred packages
* Review the files in `config/` to configure your own aliases, preferences, etc.
- Edit `config-install.yaml` to reflect your preferred packages
- Review the files in `config/` to configure your own aliases, preferences, etc.
#### Private Files
@@ -60,6 +62,7 @@ Within the private directory you can write your own install script to configure
If `private/privateInstall.sh` exists, `install.sh` will invoke it.
## Cloning this repo to a new computer
The first step needed to use these dotfiles is to clone this repo into the $HOME directory. To make this easy, I created [a gist](https://gist.github.com/natelandau/b6ec165862277f3a7a4beff76da53a9c) which can easily be run with the following command:
```
@@ -68,12 +71,13 @@ curl -SL https://gist.githubusercontent.com/natelandau/b3e1dfba7491137f0a0f5e257
This gist creates a script `~/bootstrap.sh` in your home directory which completes the following tasks
1. Creates a new public SSH key if needed
2. Copies your public key to your clipboard
3. Opens Github to allow you to add this public key to your 'known keys'
4. Clones this dotfiles repo to your home directory
1. Creates a new public SSH key if needed
2. Copies your public key to your clipboard
3. Opens Github to allow you to add this public key to your 'known keys'
4. Clones this dotfiles repo to your home directory
See. Easy. Now you're ready to run `~/dotfiles/install.sh` and get your new computer working.
### A Note on Code Reuse
Many of the scripts, configuration files, and other information herein were created by me over many years without ever having the intention to make them public. As a novice programmer, I have Googled, GitHubbed, and StackExchanged a path to solve my own scripting needs. Quite often I would lift a function whole-cloth from a GitHub repo and not keep track of it's 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 of making this repository public is not to take credit for the wonderful code written by others. If you recognize or wrote something here that I didn't credit, please let me know.

View File

@@ -21,7 +21,6 @@ _setColors_() {
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)
@@ -30,7 +29,6 @@ _setColors_() {
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)
@@ -45,7 +43,6 @@ _setColors_() {
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"
@@ -210,10 +207,17 @@ _printFuncStack_() {
# NOTE:
# Does not print functions from the alert class
local _i
_funcStackResponse=()
declare -a _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]}")
case "${FUNCNAME[${_i}]}" in
_alert_ | _trapCleanup_ | fatal | error | warning | notice | info | debug | dryrun | header | success)
continue
;;
*)
_funcStackResponse+=("${FUNCNAME[${_i}]}:$(basename "${BASH_SOURCE[${_i}]}"):${BASH_LINENO[_i - 1]}")
;;
esac
done
printf "( "
printf %s "${_funcStackResponse[0]}"
@@ -319,7 +323,7 @@ _clearLine_() {
# USAGE:
# _clearLine_ "2"
[ ! "$(declare -f "_isTerminal_")" ] && fatal "${FUNCNAME[0]} needs function _isTerminal_"
! declare -f _isTerminal_ &>/dev/null && fatal "${FUNCNAME[0]} needs function _isTerminal_"
local i
if _isTerminal_; then

View File

@@ -19,7 +19,7 @@ _dedupeArray_() {
declare -a _uniqueArray
local _i
for _i in "$@"; do
{ [[ -z ${_i} || ${_tmpArray[${_i}]:-} ]]; } && continue
{ [[ -z ${_i} || -n ${_tmpArray[${_i}]:-} ]]; } && continue
_uniqueArray+=("${_i}") && _tmpArray[${_i}]=x
done
printf '%s\n' "${_uniqueArray[@]}"
@@ -50,13 +50,16 @@ _forEachDo_() {
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
[ ! "$(declare -f "${_func}")" ] && fatal "${FUNCNAME[0]} could not find function ${_func}"
if declare -f "${_func}" &>/dev/null; then
eval "${_func}" "'${_it}'"
else
fatal "${FUNCNAME[0]} could not find function ${_func}"
fi
fi
declare -i _ret="$?"
if [[ ${_ret} -ne 0 ]]; then
return ${_ret}
return "${_ret}"
fi
done
}
@@ -85,9 +88,12 @@ _forEachValidate_() {
if [[ ${_func} == *"$"* ]]; then
eval "${_func}"
else
[ ! "$(declare -f "${_func}")" ] && fatal "${FUNCNAME[0]} could not find function ${_func}"
if ! declare -f "${_func}"; then
fatal "${FUNCNAME[0]} could not find function ${_func}"
else
eval "${_func}" "'${_it}'"
fi
fi
declare -i _ret="$?"
if [[ ${_ret} -ne 0 ]]; then
@@ -255,7 +261,7 @@ _inArray_() {
case ${opt} in
i | I)
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive regex
;;
*) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;;
@@ -410,14 +416,14 @@ _setDiff_() {
declare -a _setdiffC=()
for _a in "${_setdiffA[@]}"; do
_skip=
_skip=0
for _b in "${_setdiffB[@]}"; do
if [[ ${_a} == "${_b}" ]]; then
_skip=1
break
fi
done
[[ "${_skip}" ]] || _setdiffC=("${_setdiffC[@]}" "${_a}")
[[ ${_skip} -eq 1 ]] || _setdiffC=("${_setdiffC[@]}" "${_a}")
done
if [[ ${#_setdiffC[@]} == 0 ]]; then

View File

@@ -112,7 +112,7 @@ _isEmail_() {
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive regex
local _emailRegex
@@ -280,7 +280,7 @@ _rootAvailable_() {
elif [[ -z ${1:-} ]]; then
debug 'Sudo: Updating cached credentials ...'
if sudo -v; then
if [[ $(sudo -H -- "$BASH" -c 'printf "%s" "$EUID"') -eq 0 ]]; then
if [[ $(sudo -H -- "${BASH}" -c 'printf "%s" "$EUID"') -eq 0 ]]; then
_superuser=true
else
_superuser=false

View File

@@ -231,7 +231,7 @@ _parseDate_() {
PARSE_DATE_DAY="" PARSE_DATE_HOUR="" PARSE_DATE_MINUTE=""
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive regex
debug "_parseDate_() input: ${_stringToTest}"
@@ -446,7 +446,7 @@ _parseDate_() {
# # MMDD or DDYY
# elif [[ "${_stringToTest}" =~ .*(([0-9]{2})([0-9]{2})).* ]]; then
# debug "regex match: ${tan}MMDD or DDMM${purple}"
# debug "regex match: MMDD or DDMM"
# PARSE_DATE_FOUND="${BASH_REMATCH[1]}"
# # Figure out if days are months or vice versa
@@ -496,17 +496,6 @@ _parseDate_() {
[[ -z ${PARSE_DATE_MINUTE:-} ]] || debug "\$PARSE_DATE_MINUTE: ${PARSE_DATE_MINUTE}"
shopt -u nocasematch
# Output results for BATS tests
if [ "${automated_test_in_progress:-}" ]; then
echo "PARSE_DATE_FOUND: ${PARSE_DATE_FOUND}"
echo "PARSE_DATE_YEAR: ${PARSE_DATE_YEAR}"
echo "PARSE_DATE_MONTH: ${PARSE_DATE_MONTH}"
echo "PARSE_DATE_MONTH_NAME: ${PARSE_DATE_MONTH_NAME}"
echo "PARSE_DATE_DAY: ${PARSE_DATE_DAY}"
echo "PARSE_DATE_HOUR: ${PARSE_DATE_HOUR}"
echo "PARSE_DATE_MINUTE: ${PARSE_DATE_MINUTE}"
fi
}
_readableUnixTimestamp_() {
@@ -570,5 +559,5 @@ _toSeconds_() {
_s="$3"
fi
printf "%s\n" "$((10#$_h * 3600 + 10#$_m * 60 + 10#$_s))"
printf "%s\n" "$((10#${_h} * 3600 + 10#${_m} * 60 + 10#${_s}))"
}

View File

@@ -56,11 +56,11 @@ _printArray_() {
local _lineNumber="${2:-}"
declare -n _arr="${1}"
[[ ${VERBOSE} != true ]] && return 0
[[ ${VERBOSE:-} != true ]] && return 0
debug "Printing contents of \${${_arrayName}[@]}" "${_lineNumber}"
for _k in "${!_arr[@]}"; do
debug "${_k} = ${_arr[$_k]}"
debug "${_k} = ${_arr[${_k}]}"
done
}

View File

@@ -48,34 +48,29 @@ _backupFile_() {
local _newFilename
# Error handling
[ ! "$(declare -f "_execute_")" ] \
&& {
fatal "_backupFile_ needs function _execute_"
}
[ ! "$(declare -f "_createUniqueFilename_")" ] \
&& {
fatal "_backupFile_ needs function _createUniqueFilename_"
}
declare -f _execute_ &>/dev/null || fatal "_backupFile_ needs function _execute_"
declare -f _createUniqueFilename_ &>/dev/null || fatal "_backupFile_ needs function _createUniqueFilename_"
[ ! -e "${_fileToBackup}" ] \
&& {
debug "Source '${_fileToBackup}' not found"
return 1
}
if [ ${_useDirectory} == true ]; then
if [[ ${_useDirectory} == true ]]; then
[ ! -d "${_backupDir}" ] \
&& _execute_ "mkdir -p \"${_backupDir}\"" "Creating backup directory"
_newFilename="$(_createUniqueFilename_ "${_backupDir}/${_fileToBackup#.}")"
if [ ${_moveFile} == true ]; then
if [[ ${_moveFile} == true ]]; then
_execute_ "mv \"${_fileToBackup}\" \"${_backupDir}/${_newFilename##*/}\"" "Moving: '${_fileToBackup}' to '${_backupDir}/${_newFilename##*/}'"
else
_execute_ "cp -R \"${_fileToBackup}\" \"${_backupDir}/${_newFilename##*/}\"" "Backing up: '${_fileToBackup}' to '${_backupDir}/${_newFilename##*/}'"
fi
else
_newFilename="$(_createUniqueFilename_ "${_fileToBackup}.bak")"
if [ ${_moveFile} == true ]; then
if [[ ${_moveFile} == true ]]; then
_execute_ "mv \"${_fileToBackup}\" \"${_newFilename}\"" "Moving '${_fileToBackup}' to '${_newFilename}'"
else
_execute_ "cp -R \"${_fileToBackup}\" \"${_newFilename}\"" "Backing up '${_fileToBackup}' to '${_newFilename}'"
@@ -110,10 +105,8 @@ _createUniqueFilename_() {
case ${opt} in
i | I) _internalInteger=true ;;
*)
{
error "Unrecognized option '${1}' passed to _createUniqueFilename_" "${LINENO}"
error "Unrecognized option '${1}' passed to ${FUNCNAME[0]}" "${LINENO}"
return 1
}
;;
esac
done
@@ -142,7 +135,7 @@ _createUniqueFilename_() {
_originalFile="$(basename "${_fullFile}")"
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive regex
# Detect some common multi-extensions
@@ -155,18 +148,18 @@ _createUniqueFilename_() {
_fn="${_originalFile}"
for ((i = 0; i < _levels; i++)); do
_ext=${_fn##*.}
if [[ $i == 0 ]]; then
if [[ ${i} == 0 ]]; then
_extension=${_ext}${_extension:-}
else
_extension=${_ext}.${_extension:-}
fi
_fn=${_fn%.$_ext}
_fn=${_fn%.${_ext}}
done
if [[ ${_extension} == "${_originalFile}" ]]; then
_extension=""
else
_originalFile="${_originalFile%.$_extension}"
_originalFile="${_originalFile%.${_extension}}"
_extension=".${_extension}"
fi
@@ -212,9 +205,9 @@ _decryptFile_() {
local _fileToDecrypt="${1:?_decryptFile_ needs a file}"
local _defaultName="${_fileToDecrypt%.enc}"
local _decryptedFile="${2:-$_defaultName.decrypt}"
local _decryptedFile="${2:-${_defaultName}.decrypt}"
[ ! "$(declare -f "_execute_")" ] && fatal "need function _execute_"
declare -f _execute_ &>/dev/null || fatal "${FUNCNAME[0]} needs function _execute_"
if ! command -v openssl &>/dev/null; then
fatal "openssl not found"
@@ -247,13 +240,13 @@ _encryptFile_() {
local _fileToEncrypt="${1:?_encodeFile_ needs a file}"
local _defaultName="${_fileToEncrypt%.decrypt}"
local _encryptedFile="${2:-$_defaultName.enc}"
local _encryptedFile="${2:-${_defaultName}.enc}"
[[ $# == 0 ]] && fatal "Missing required argument to ${FUNCNAME[0]}"
[ ! -f "${_fileToEncrypt}" ] && return 1
[ ! "$(declare -f "_execute_")" ] && fatal "need function _execute_"
declare -f _execute_ &>/dev/null || fatal "${FUNCNAME[0]} needs function _execute_"
if ! command -v openssl &>/dev/null; then
fatal "openssl not found"
@@ -295,7 +288,7 @@ _extractArchive_() {
set -- "$@" "${1:0:-2}"
;;
*.bz2) bunzip2 "$1" ;;
*.deb) dpkg-deb -x${_vv} "$1" "${1:0:-4}" ;;
*.deb) dpkg-deb -x"${_vv}" "$1" "${1:0:-4}" ;;
*.pax.gz)
gunzip "$1"
set -- "$@" "${1:0:-3}"
@@ -304,7 +297,7 @@ _extractArchive_() {
*.pax) pax -r -f "$1" ;;
*.pkg) pkgutil --expand "$1" "${1:0:-4}" ;;
*.rar) unrar x "$1" ;;
*.rpm) rpm2cpio "$1" | cpio -idm${_vv} ;;
*.rpm) rpm2cpio "$1" | cpio -idm"${_vv}" ;;
*.tar) tar "x${_vv}f" "$1" ;;
*.txz)
mv "$1" "${1:0:-4}.tar.xz"
@@ -388,15 +381,15 @@ _fileExtension_() {
esac
fi
_fn="$_file"
_fn="${_file}"
for ((i = 0; i < _levels; i++)); do
_ext=${_fn##*.}
if [[ $i == 0 ]]; then
if [[ ${i} == 0 ]]; then
_exts=${_ext}${_exts:-}
else
_exts=${_ext}.${_exts:-}
fi
_fn=${_fn%.$_ext}
_fn=${_fn%.${_ext}}
done
[[ ${_file} == "${_exts}" ]] && return 1
@@ -543,7 +536,7 @@ _makeSymlink_() {
local _onlyShowChanged=false
while getopts ":cCnNsS" opt; do
case $opt in
case ${opt} in
n | N) _backupOriginal=false ;;
s | S) _useSudo=true ;;
c | C) _onlyShowChanged=true ;;
@@ -552,12 +545,12 @@ _makeSymlink_() {
done
shift $((OPTIND - 1))
[ ! "$(declare -f "_backupFile_")" ] && fatal "${FUNCNAME[0]} needs function _backupFile_"
[ ! "$(declare -f "_execute_")" ] && fatal "${FUNCNAME[0]} needs function _execute_"
declare -f _execute_ &>/dev/null || fatal "${FUNCNAME[0]} needs function _execute_"
declare -f _backupFile_ &>/dev/null || fatal "${FUNCNAME[0]} needs function _backupFile_"
if ! command -v realpath >/dev/null 2>&1; then
error "We must have 'realpath' installed and available in \$PATH to run."
if [[ $OSTYPE == "darwin"* ]]; then
if [[ ${OSTYPE} == "darwin"* ]]; then
notice "Install coreutils using homebrew and rerun this script."
info "\t$ brew install coreutils"
fi
@@ -571,10 +564,10 @@ _makeSymlink_() {
local _originalFile
# Fix files where $HOME is written as '~'
_destinationFile="${_destinationFile/\~/$HOME}"
_sourceFile="${_sourceFile/\~/$HOME}"
_destinationFile="${_destinationFile/\~/${HOME}}"
_sourceFile="${_sourceFile/\~/${HOME}}"
[ ! -e "$_sourceFile" ] \
[ ! -e "${_sourceFile}" ] \
&& {
error "'${_sourceFile}' not found"
return 1
@@ -595,9 +588,9 @@ _makeSymlink_() {
_originalFile="$(realpath "${_destinationFile}")"
[[ ${_originalFile} == "${_sourceFile}" ]] && {
if [ ${_onlyShowChanged} == true ]; then
if [[ ${_onlyShowChanged} == true ]]; then
debug "Symlink already exists: ${_sourceFile}${_destinationFile}"
elif [ "${DRYRUN}" == true ]; then
elif [[ ${DRYRUN:-} == true ]]; then
dryrun "Symlink already exists: ${_sourceFile}${_destinationFile}"
else
info "Symlink already exists: ${_sourceFile}${_destinationFile}"
@@ -693,7 +686,7 @@ _readFile_() {
local _result
local _fileToRead="$1"
[ ! -f "$_fileToRead" ] \
[ ! -f "${_fileToRead}" ] \
&& {
error "'${_fileToRead}' not found"
return 1

View File

@@ -62,10 +62,8 @@ _useGNUutils_() {
# NOTES:
# GNU utilities can be added to MacOS using Homebrew
[ ! "$(declare -f "_setPATH_")" ] && fatal "${FUNCNAME[0]} needs function _setPATH_"
[ ! "$(declare -f "_detectOS_")" ] && fatal "${FUNCNAME[0]} needs function _detectOS_"
! declare -f "_setPATH_" &>/dev/null && fatal "${FUNCNAME[0]} needs function _setPATH_"
if [[ $(_detectOS_) == mac ]]; then
if _setPATH_ \
"/usr/local/opt/gnu-tar/libexec/gnubin" \
"/usr/local/opt/coreutils/libexec/gnubin" \
@@ -75,8 +73,5 @@ _useGNUutils_() {
else
return 1
fi
else
# Always return 0 on non-MacOS
return 0
fi
}

View File

@@ -71,7 +71,7 @@ _detectLinuxDistro_() {
local _distro
if [[ -f /etc/os-release ]]; then
# shellcheck disable=SC1091
# shellcheck disable=SC1091,SC2154
. "/etc/os-release"
_distro="${NAME}"
elif type lsb_release >/dev/null 2>&1; then
@@ -79,7 +79,7 @@ _detectLinuxDistro_() {
_distro=$(lsb_release -si)
elif [[ -f /etc/lsb-release ]]; then
# For some versions of Debian/Ubuntu without lsb_release command
# shellcheck disable=SC1091
# shellcheck disable=SC1091,SC2154
. /etc/lsb-release
_distro="${DISTRIB_ID}"
elif [[ -f /etc/debian_version ]]; then
@@ -111,7 +111,7 @@ _detectMacOSVersion_() {
# CREDIT:
# https://github.com/labbots/bash-utility
[ ! "$(declare -f "_detectOS_")" ] && fatal "${FUNCNAME[0]} needs function _detectOS_"
declare -f _detectOS_ &>/dev/null || fatal "${FUNCNAME[0]} needs function _detectOS_"
if [[ "$(_detectOS_)" == "mac" ]]; then
local _mac_version
@@ -198,7 +198,7 @@ _execute_() {
local OPTIND=1
while getopts ":vVpPeEsSqQnN" opt; do
case $opt in
case ${opt} in
v | V) _localVerbose=true ;;
p | P) _passFailures=true ;;
e | E) _echoResult=true ;;
@@ -225,7 +225,7 @@ _execute_() {
VERBOSE=true
fi
if "${DRYRUN}"; then
if "${DRYRUN:-}"; then
if "${_quietMode}"; then
VERBOSE=${_saveVerbose}
return 0
@@ -235,7 +235,7 @@ _execute_() {
else
dryrun "${1}" "$(caller)"
fi
elif ${VERBOSE}; then
elif ${VERBOSE:-}; then
if eval "${_command}"; then
if "${_quietMode}"; then
VERBOSE=${_saveVerbose}
@@ -274,7 +274,7 @@ _execute_() {
fi
else
if "${_quietMode}"; then
VERBOSE=$_saveVerbose
VERBOSE=${_saveVerbose}
elif "${_echoResult}"; then
printf "%s\n" "error: ${_executeMessage}"
else
@@ -303,9 +303,11 @@ _findBaseDir_() {
local _dir
# Is file sourced?
[[ $_ != "$0" ]] \
&& _source="${BASH_SOURCE[1]}" \
|| _source="${BASH_SOURCE[0]}"
if [[ ${_} != "${0}" ]]; then
_source="${BASH_SOURCE[1]}"
else
_source="${BASH_SOURCE[0]}"
fi
while [ -h "${_source}" ]; do # Resolve $SOURCE until the file is no longer a symlink
_dir="$(cd -P "$(dirname "${_source}")" && pwd)"
@@ -337,9 +339,9 @@ _generateUUID_() {
for ((n = 0; n < 16; ++n)); do
_b="$((RANDOM % 256))"
case "$n" in
case "${n}" in
6) printf '4%x' "$((_b % 16))" ;;
8) printf '%c%x' "${_c:$RANDOM%${#_c}:1}" "$((_b % 16))" ;;
8) printf '%c%x' "${_c:${RANDOM}%${#_c}:1}" "$((_b % 16))" ;;
3 | 5 | 7 | 9)
printf '%02x-' "${_b}"
@@ -368,8 +370,8 @@ _makeProgressBar_() {
# done
[[ $# == 0 ]] && return # Do nothing if no arguments are passed
(${QUIET}) && return
(${VERBOSE}) && return
(${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
@@ -390,7 +392,7 @@ _makeProgressBar_() {
tput civis # Hide the cursor
trap 'tput cnorm; exit 1' SIGINT
if [[ ! ${progressBarProgress} -eq $n ]]; then
if [[ ! ${progressBarProgress} -eq ${n} ]]; then
#echo "progressBarProgress: $progressBarProgress"
# Compute the percentage.
_percentage=$((progressBarProgress * 100 / $1))
@@ -398,8 +400,8 @@ _makeProgressBar_() {
_num=$((progressBarProgress * _width / $1))
# Create the progress bar string.
_bar=""
if [ ${_num} -gt 0 ]; then
_bar=$(printf "%0.s${_barCharacter}" $(seq 1 ${_num}))
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}")
@@ -465,7 +467,7 @@ _seekConfirmation_() {
local _yesNo
input "${1}"
if "${FORCE}"; then
if "${FORCE:-}"; then
debug "Forcing confirmation with '--force' flag set"
printf "%s\n" " "
return 0

View File

@@ -42,7 +42,7 @@ _httpStatus_() {
--no-keepalive "${_curlops}" --output /dev/null "${_url}")
# __________ get the STATUS (from code) which is human interpretable:
case $_code in
case ${_code} in
000) _status="Not responding within ${_timeout} seconds" ;;
100) _status="Informational: Continue" ;;
101) _status="Informational: Switching Protocols" ;;

View File

@@ -35,7 +35,7 @@ _cleanString_() {
local OPTIND=1
while getopts ":lLuUaAsSpP" opt; do
case $opt in
case ${opt} in
l | L) _lc=true ;;
u | U) _uc=true ;;
a | A) _alphanumeric=true ;;
@@ -69,8 +69,8 @@ _cleanString_() {
local i
for i in "${_arrayToClean[@]}"; do
debug "cleaning: $i"
_string="$(printf "%s" "${_string}" | sed "s/$i//g")"
debug "cleaning: ${i}"
_string="$(printf "%s" "${_string}" | sed "s/${i}//g")"
done
("${_lc}") \
@@ -258,7 +258,7 @@ _regexCapture_() {
case ${opt} in
i | I)
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive regex
;;
*) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;;
@@ -332,7 +332,7 @@ _stringContains_() {
case ${opt} in
i | I)
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive searching
;;
*) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;;
@@ -370,7 +370,7 @@ _stringRegex_() {
case ${opt} in
i | I)
#shellcheck disable=SC2064
trap "$(shopt -p nocasematch)" RETURN # reset nocasematch when function exits
trap '$(shopt -p nocasematch)' RETURN # reset nocasematch when function exits
shopt -s nocasematch # Use case-insensitive regex
;;
*) fatal "Unrecognized option '${1}' passed to ${FUNCNAME[0]}. Exiting." ;;

View File

@@ -1,6 +1,7 @@
# Functions required to allow the script template and alert functions to be used
# shellcheck disable=SC2154
# shellcheck disable=SC2120
_acquireScriptLock_() {
# DESC:
# Acquire script lock to prevent running the same script a second time before the
@@ -17,18 +18,18 @@ _acquireScriptLock_() {
if [[ ${1:-} == 'system' ]]; then
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").lock"
else
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").$UID.lock"
_lockDir="${TMPDIR:-/tmp/}$(basename "$0").${UID}.lock"
fi
if command mkdir "${LOCK_DIR}" 2>/dev/null; then
if command mkdir "${_lockDir}" 2>/dev/null; then
readonly SCRIPT_LOCK="${_lockDir}"
debug "Acquired script lock: ${tan}${SCRIPT_LOCK}${purple}"
debug "Acquired script lock: ${yellow}${SCRIPT_LOCK}${purple}"
else
if [ "$(declare -f "_safeExit_")" ]; then
error "Unable to acquire script lock: ${yellow}${LOCK_DIR}${red}"
if declare -f "_safeExit_" &>/dev/null; then
error "Unable to acquire script lock: ${yellow}${_lockDir}${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}"
printf "%s\n" "ERROR: Could not acquire script lock. If you trust the script isn't running, delete: ${_lockDir}"
exit 1
fi
@@ -70,7 +71,7 @@ _safeExit_() {
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}'"
warning "Script lock could not be removed. Try manually deleting ${yellow}'${SCRIPT_LOCK}'"
fi
fi