Improve option parsing and command detection.

This commit is contained in:
William Melody 2020-04-08 17:44:06 -07:00
parent 5d9f876b13
commit 7301dc38f1
1 changed files with 115 additions and 94 deletions

209
hosts
View File

@ -138,99 +138,6 @@ die() {
_die echo "${@}"
}
###############################################################################
# Options
#
# NOTE: The `getops` builtin command only parses short options and BSD `getopt`
# does not support long arguments (GNU `getopt` does), so the most portable
# and clear way to parse options is often to just use a `while` loop.
#
# For a pure bash `getopt` function, try pure-getopt:
# https://github.com/agriffis/pure-getopt
#
# More info:
# http://wiki.bash-hackers.org/scripting/posparams
# http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
# http://stackoverflow.com/a/14203146
# http://stackoverflow.com/a/7948533
# https://stackoverflow.com/a/12026302
# https://stackoverflow.com/a/402410
###############################################################################
# Get raw options for any commands that expect them.
_RAW_OPTIONS="${*:-}"
# Parse Options ###############################################################
# Initialize $_COMMAND_ARGV array
#
# This array contains all of the arguments that get passed along to each
# command. This is essentially the same as the program arguments, minus those
# that have been filtered out in the program option parsing loop. This array
# is initialized with $0, which is the program's name.
_COMMAND_ARGV=("${0}")
# Initialize $_CMD and `$_USE_DEBUG`, which can continue to be blank depending
# on what the program needs.
_CMD=""
_USE_DEBUG=0
_AUTO_SUDO=0
while [[ ${#} -gt 0 ]]
do
__opt="${1}"
shift
case "${__opt}" in
-h|--help)
_CMD="help"
;;
--version)
_CMD="version"
;;
--debug)
_USE_DEBUG=1
;;
--auto-sudo|--sudo)
_AUTO_SUDO=1
;;
*)
# The first non-option argument is assumed to be the command name.
# All subsequent arguments are added to $_COMMAND_ARGV.
if [[ -n "${_CMD:-}" ]]
then
_COMMAND_ARGV+=("${__opt}")
else
_CMD="${__opt}"
fi
;;
esac
done
# Set $_COMMAND_PARAMETERS to $_COMMAND_ARGV, minus the initial element, $0. This
# provides an array that is equivalent to $* and $@ within each command
# function, though the array is zero-indexed, which could lead to confusion.
#
# Use `unset` to remove the first element rather than slicing (e.g.,
# `_COMMAND_PARAMETERS=("${_COMMAND_ARGV[@]:1}")`) because under bash 3.2 the
# resulting slice is treated as a quoted string and doesn't easily get coaxed
# into a new array.
_COMMAND_PARAMETERS=("${_COMMAND_ARGV[@]}")
unset "_COMMAND_PARAMETERS[0]"
_debug printf \
"\${_CMD}: %s\\n" \
"${_CMD}"
_debug printf \
"\${_RAW_OPTIONS} (one per line):\\n%s\\n" \
"${_RAW_OPTIONS}"
_debug printf \
"\${_COMMAND_ARGV[*]}: %s\\n" \
"${_COMMAND_ARGV[*]}"
_debug printf \
"\${_COMMAND_PARAMETERS[*]:-}: %s\\n" \
"${_COMMAND_PARAMETERS[*]:-}"
###############################################################################
# Environment
###############################################################################
@ -331,7 +238,7 @@ _main() {
if _contains "${_CMD}" "${_DEFINED_COMMANDS[*]:-}"
then
# Pass all comment arguments to the program except for the first ($0).
${_CMD} "${_COMMAND_PARAMETERS[@]:-}"
"${_CMD}" "${_COMMAND_PARAMETERS[@]:-}"
else
_die printf "Unknown command: %s\\n" "${_CMD}"
fi
@ -1478,6 +1385,120 @@ unblock() {
done
}
###############################################################################
# Options
#
# NOTE: The `getops` builtin command only parses short options and BSD `getopt`
# does not support long arguments (GNU `getopt` does), so the most portable
# and clear way to parse options is often to just use a `while` loop.
#
# For a pure bash `getopt` function, try pure-getopt:
# https://github.com/agriffis/pure-getopt
#
# More info:
# http://wiki.bash-hackers.org/scripting/posparams
# http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html
# http://stackoverflow.com/a/14203146
# http://stackoverflow.com/a/7948533
# https://stackoverflow.com/a/12026302
# https://stackoverflow.com/a/402410
###############################################################################
# Get raw options for any commands that expect them.
_RAW_OPTIONS="${*:-}"
# Parse Options ###############################################################
# Initialize $_COMMAND_ARGV array
#
# This array contains all of the arguments that get passed along to each
# command. This is essentially the same as the program arguments, minus those
# that have been filtered out in the program option parsing loop. This array
# is initialized with $0, which is the program's name.
_COMMAND_ARGV=("${0}")
# Initialize $_CMD and `$_USE_DEBUG`, which can continue to be blank depending
# on what the program needs.
_CMD=""
_USE_DEBUG=0
_AUTO_SUDO=0
_SUBCOMMANDS=(
add
backups
block
commands
disable
disabled
edit
enable
enabled
file
help
list
remove
search
show
unblock
version
)
_SUBCOMMANDS_PATTERN="$(_join '|' "${_SUBCOMMANDS[@]}")"
while [[ ${#} -gt 0 ]]
do
__opt="${1}"
shift
case "${__opt}" in
-h|--help)
_CMD="help"
;;
--version)
_CMD="version"
;;
--debug)
_USE_DEBUG=1
;;
--auto-sudo|--sudo)
_AUTO_SUDO=1
;;
*)
# The first non-option argument is assumed to be the command name.
# All subsequent arguments are added to $_COMMAND_ARGV.
if [[ -z "${_CMD:-}" ]] && [[ "${__opt:-}" =~ ${_SUBCOMMANDS_PATTERN} ]]
then
_CMD="${__opt}"
else
_COMMAND_ARGV+=("${__opt}")
fi
;;
esac
done
# Set $_COMMAND_PARAMETERS to $_COMMAND_ARGV, minus the initial element, $0. This
# provides an array that is equivalent to $* and $@ within each command
# function, though the array is zero-indexed, which could lead to confusion.
#
# Use `unset` to remove the first element rather than slicing (e.g.,
# `_COMMAND_PARAMETERS=("${_COMMAND_ARGV[@]:1}")`) because under bash 3.2 the
# resulting slice is treated as a quoted string and doesn't easily get coaxed
# into a new array.
_COMMAND_PARAMETERS=("${_COMMAND_ARGV[@]}")
unset "_COMMAND_PARAMETERS[0]"
_debug printf \
"\${_CMD}: %s\\n" \
"${_CMD}"
_debug printf \
"\${_RAW_OPTIONS} (one per line):\\n%s\\n" \
"${_RAW_OPTIONS}"
_debug printf \
"\${_COMMAND_ARGV[*]}: %s\\n" \
"${_COMMAND_ARGV[*]}"
_debug printf \
"\${_COMMAND_PARAMETERS[*]:-}: %s\\n" \
"${_COMMAND_PARAMETERS[*]:-}"
###############################################################################
# Run Program
###############################################################################